Merge "aapt2: Add a new flag '--revision-code'"
diff --git a/Android.bp b/Android.bp
index 8164d6a..c47b747 100644
--- a/Android.bp
+++ b/Android.bp
@@ -747,6 +747,7 @@
 
     srcs: [
         ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
         "core/proto/**/*.proto",
         "libs/incident/**/*.proto",
     ],
@@ -773,6 +774,7 @@
 
     srcs: [
         ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
         "core/proto/**/*.proto",
         "libs/incident/**/*.proto",
     ],
@@ -912,13 +914,18 @@
     name: "platformprotos",
     srcs: [
         ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_internal_protos",
         "cmds/am/proto/instrumentation_data.proto",
         "cmds/statsd/src/**/*.proto",
         "core/proto/**/*.proto",
         "libs/incident/proto/**/*.proto",
     ],
     proto: {
-        include_dirs: ["external/protobuf/src"],
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
         type: "full",
     },
     // Protos have lots of MissingOverride and similar.
@@ -943,6 +950,7 @@
     sdk_version: "9",
     srcs: [
         ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
         "core/proto/**/*.proto",
         "libs/incident/proto/android/os/**/*.proto",
     ],
@@ -958,6 +966,7 @@
 
     srcs: [
         ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
         "core/proto/**/*.proto",
         "libs/incident/proto/android/os/**/*.proto",
     ],
@@ -979,7 +988,9 @@
 
     proto: {
         export_proto_headers: true,
-        include_dirs: ["external/protobuf/src"],
+        include_dirs: [
+            "external/protobuf/src",
+        ],
     },
 
     cflags: [
@@ -990,6 +1001,7 @@
 
     srcs: [
         ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
         "core/proto/**/*.proto",
     ],
 }
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
index 303c667..2b7af2f 100644
--- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
@@ -23,11 +23,14 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.inputmethodservice.InputMethodService;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.SystemClock;
 import android.perftests.utils.ManualBenchmarkState;
 import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
@@ -88,7 +91,7 @@
             "ISC.onPostLayout"
     };
 
-     /** IMF show methods to log in trace. */
+    /** IMF show methods to log in trace. */
     private String[] mShowMethods = {
             "IC.showRequestFromIme",
             "IC.showRequestFromApi",
@@ -99,7 +102,23 @@
             "IMMS.showSoftInput",
             "IMS.showSoftInput",
             "IMS.startInput",
-            "WMS.showImePostLayout"
+            "WMS.showImePostLayout",
+            "IMS.updateFullscreenMode",
+            "IMS.onComputeInsets",
+            "IMS.showWindow"
+    };
+
+    /** IMF show methods to log in trace. */
+    private String[] mShowMethodsCold = {
+            "IMS.bindInput",
+            "IMS.initializeInternal",
+            "IMS.restartInput",
+            "IMS.onCreate",
+            "IMS.initSoftInputWindow",
+            "IMS.resetStateForNewConfiguration",
+            "IMMS.onServiceConnected",
+            "IMMS.sessionCreated",
+            "IMMS.startInputOrWindowGainedFocus"
     };
 
     /** IMF hide lifecycle methods to log in trace. */
@@ -163,6 +182,7 @@
     public static class BaselineIme extends InputMethodService {
 
         public static final int HEIGHT_DP = 100;
+        private static int sPid;
 
         @Override
         public View onCreateInputView() {
@@ -173,9 +193,14 @@
             view.setPadding(0, 0, 0, 0);
             view.addView(inner, new FrameLayout.LayoutParams(MATCH_PARENT, height));
             inner.setBackgroundColor(0xff01fe10); // green
+            sPid = Process.myPid();
             return view;
         }
 
+        static int getPid() {
+            return sPid;
+        }
+
         static ComponentName getName(Context context) {
             return new ComponentName(context, BaselineIme.class);
         }
@@ -188,8 +213,8 @@
                     flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
                             | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
                             | StatsReport.FLAG_COEFFICIENT_VAR))
-    public void testShowIme() throws Throwable {
-        testShowOrHideIme(true /* show */);
+    public void testShowImeWarm() throws Throwable {
+        testShowOrHideImeWarm(true /* show */);
     }
 
     @Test
@@ -200,10 +225,65 @@
                             | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
                             | StatsReport.FLAG_COEFFICIENT_VAR))
     public void testHideIme() throws Throwable {
-        testShowOrHideIme(false /* show */);
+        testShowOrHideImeWarm(false /* show */);
     }
 
-    private void testShowOrHideIme(final boolean show) throws Throwable {
+    @Test
+    @ManualBenchmarkTest(
+            targetTestDurationNs = 10 * TIME_1_S_IN_NS,
+            statsReport = @StatsReport(
+                    flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
+                            | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
+                            | StatsReport.FLAG_COEFFICIENT_VAR))
+    public void testShowImeCold() throws Throwable {
+        mTraceMethods = new TraceMarkParser(
+                buildArray(mCommonMethods, mShowMethods, mShowMethodsCold));
+
+        final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        state.setCustomizedIterations(getProfilingIterations(), this);
+        if (state.isWarmingUp()) {
+            // we don't need to warmup for cold start.
+            return;
+        }
+
+        long measuredTimeNs = 0;
+        while (state.keepRunning(measuredTimeNs)) {
+            killBaselineIme();
+            try (ImeSession imeSession = new ImeSession(BaselineIme.getName(
+                    getInstrumentation().getContext()))) {
+                final AtomicReference<CountDownLatch> latchStart = new AtomicReference<>();
+                final Activity activity = getActivityWithFocus();
+
+                setImeListener(activity, latchStart, null /* latchEnd */);
+                latchStart.set(new CountDownLatch(1));
+
+                if (!mIsTraceStarted) {
+                    startAsyncAtrace();
+                }
+
+                final WindowInsetsController controller =
+                        activity.getWindow().getDecorView().getWindowInsetsController();
+                AtomicLong startTime = new AtomicLong();
+                activity.runOnUiThread(() -> {
+                    startTime.set(SystemClock.elapsedRealtimeNanos());
+                    controller.show(WindowInsets.Type.ime());
+                });
+
+                measuredTimeNs = waitForAnimationStart(latchStart, startTime);
+                mActivityRule.finishActivity();
+            }
+        }
+        stopAsyncAtrace();
+        addResultToState(state);
+    }
+
+    private void killBaselineIme() {
+        assertTrue("PID of test and IME can't be same",
+                Process.myPid() != BaselineIme.getPid());
+        Process.killProcess(BaselineIme.getPid());
+    }
+
+    private void testShowOrHideImeWarm(final boolean show) throws Throwable {
         mTraceMethods = new TraceMarkParser(buildArray(
                 mCommonMethods, show ? mShowMethods : mHideMethods));
         final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.aidl
similarity index 80%
copy from location/java/android/location/timezone/LocationTimeZoneEvent.aidl
copy to apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.aidl
index 5386588..4686de8 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.aidl
@@ -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,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.app.appsearch;
 
-package android.location.timezone;
-
-parcelable LocationTimeZoneEvent;
+/** {@hide} */
+parcelable AppSearchBatchResult;
\ No newline at end of file
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index f2c9942..e57359f 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -15,10 +15,12 @@
  */
 package android.app.appsearch;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.ParcelableException;
 import android.os.RemoteException;
 
 import com.android.internal.infra.AndroidFuture;
@@ -27,7 +29,10 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * This class provides access to the centralized AppSearch index maintained by the system.
@@ -40,12 +45,99 @@
 // TODO(b/148046169): This class header needs a detailed example/tutorial.
 @SystemService(Context.APP_SEARCH_SERVICE)
 public class AppSearchManager {
-    private static final String DEFAULT_DATABASE = "";
+    /**
+     * The default empty database name.
+     * @hide
+     */
+    public static final String DEFAULT_DATABASE_NAME = "";
+
     private final IAppSearchManager mService;
 
     /** @hide */
     public AppSearchManager(@NonNull IAppSearchManager service) {
-        mService = service;
+        mService = Objects.requireNonNull(service);
+    }
+
+    /** Contains information about how to create the search session. */
+    public static final class SearchContext {
+        final String mDatabaseName;
+
+        SearchContext(@NonNull String databaseName) {
+            mDatabaseName = Objects.requireNonNull(databaseName);
+        }
+
+        /**
+         * Returns the name of the database to create or open.
+         *
+         * <p>Databases with different names are fully separate with distinct types, namespaces,
+         * and data.
+         */
+        @NonNull
+        public String getDatabaseName() {
+            return mDatabaseName;
+        }
+
+        /** Builder for {@link SearchContext} objects. */
+        public static final class Builder {
+            private String mDatabaseName = DEFAULT_DATABASE_NAME;
+            private boolean mBuilt = false;
+
+            /**
+             * Sets the name of the database associated with {@link AppSearchSession}.
+             *
+             * <p>{@link AppSearchSession} will create or open a database under the given name.
+             *
+             * <p>Databases with different names are fully separate with distinct types, namespaces,
+             * and data.
+             *
+             * <p>Database name cannot contain {@code '/'}.
+             *
+             * <p>If not specified, defaults to {@link #DEFAULT_DATABASE_NAME}.
+             * @param databaseName The name of the database.
+             * @throws IllegalArgumentException if the databaseName contains {@code '/'}.
+             */
+            @NonNull
+            public Builder setDatabaseName(@NonNull String databaseName) {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                Objects.requireNonNull(databaseName);
+                if (databaseName.contains("/")) {
+                    throw new IllegalArgumentException("Database name cannot contain '/'");
+                }
+                mDatabaseName = databaseName;
+                return this;
+            }
+
+            /** Builds a {@link SearchContext} instance. */
+            @NonNull
+            public SearchContext build() {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                mBuilt = true;
+                return new SearchContext(mDatabaseName);
+            }
+        }
+    }
+
+    /**
+     * Creates a new {@link AppSearchSession}.
+     *
+     * <p>This process requires an AppSearch native indexing file system for each user. If it's not
+     * created for this user, the initialization process will create one under user's directory.
+     *
+     * @param searchContext The {@link SearchContext} contains all information to create a new
+     *                      {@link AppSearchSession}
+     * @param executor      Executor on which to invoke the callback.
+     * @param callback      The {@link AppSearchResult}&lt;{@link AppSearchSession}&gt; of
+     *                      performing this operation. Or a {@link AppSearchResult} with failure
+     *                      reason code and error information.
+     */
+    public void createSearchSession(
+            @NonNull SearchContext searchContext,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
+        Objects.requireNonNull(searchContext);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        AppSearchSession.createSearchSession(searchContext, mService, executor, callback);
     }
 
     /**
@@ -99,7 +191,7 @@
      *
      * @param request The schema update request.
      * @return the result of performing this operation.
-     *
+     * @deprecated use {@link AppSearchSession#setSchema} instead.
      * @hide
      */
     @NonNull
@@ -113,9 +205,14 @@
         }
         AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
         try {
-            mService.setSchema(DEFAULT_DATABASE, schemaBundles, request.isForceOverride(), future);
+            mService.setSchema(DEFAULT_DATABASE_NAME, schemaBundles, request.isForceOverride(),
+                    new IAppSearchResultCallback.Stub() {
+                        public void onResult(AppSearchResult result) {
+                            future.complete(result);
+                        }
+                    });
         } catch (RemoteException e) {
-            future.completeExceptionally(e);
+            throw e.rethrowFromSystemServer();
         }
         return getFutureOrThrow(future);
     }
@@ -134,6 +231,9 @@
      * {@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.
+     * @throws RuntimeException If an error occurred during the execution.
+     *
+     * @deprecated use {@link AppSearchSession#putDocuments} instead.
      * @hide
      */
     public AppSearchBatchResult<String, Void> putDocuments(@NonNull PutDocumentsRequest request) {
@@ -146,7 +246,16 @@
         }
         AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
         try {
-            mService.putDocuments(DEFAULT_DATABASE, documentBundles, future);
+            mService.putDocuments(DEFAULT_DATABASE_NAME, documentBundles,
+                    new IAppSearchBatchResultCallback.Stub() {
+                        public void onResult(AppSearchBatchResult result) {
+                            future.complete(result);
+                        }
+
+                        public void onSystemError(ParcelableException exception) {
+                            future.completeExceptionally(exception);
+                        }
+                    });
         } catch (RemoteException e) {
             future.completeExceptionally(e);
         }
@@ -165,6 +274,9 @@
      * {@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}.
+     * @throws RuntimeException If an error occurred during the execution.
+     *
+     * @deprecated use {@link AppSearchSession#getByUri} instead.
      */
     public AppSearchBatchResult<String, GenericDocument> getByUri(
             @NonNull GetByUriRequest request) {
@@ -173,7 +285,16 @@
         List<String> uris = new ArrayList<>(request.getUris());
         AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
         try {
-            mService.getDocuments(DEFAULT_DATABASE, request.getNamespace(), uris, future);
+            mService.getDocuments(DEFAULT_DATABASE_NAME, request.getNamespace(), uris,
+                    new IAppSearchBatchResultCallback.Stub() {
+                        public void onResult(AppSearchBatchResult result) {
+                            future.complete(result);
+                        }
+
+                        public void onSystemError(ParcelableException exception) {
+                            future.completeExceptionally(exception);
+                        }
+                    });
         } catch (RemoteException e) {
             future.completeExceptionally(e);
         }
@@ -252,6 +373,9 @@
      *
      * @param queryExpression Query String to search.
      * @param searchSpec Spec for setting filters, raw query etc.
+     * @throws RuntimeException If an error occurred during the execution.
+     *
+     * @deprecated use AppSearchSession#query instead.
      * @hide
      */
     @NonNull
@@ -261,7 +385,7 @@
         //     them in one big list.
         AndroidFuture<AppSearchResult> searchResultsFuture = new AndroidFuture<>();
         try {
-            mService.query(DEFAULT_DATABASE, queryExpression,
+            mService.query(DEFAULT_DATABASE_NAME, queryExpression,
                     searchSpec.getBundle(), searchResultsFuture);
         } catch (RemoteException e) {
             searchResultsFuture.completeExceptionally(e);
@@ -278,7 +402,7 @@
     }
 
     /**
-     * Deletes {@link GenericDocument}s by URI.
+     * Removes {@link GenericDocument}s by URI.
      *
      * <p>You should not call this method directly; instead, use the {@code AppSearch#delete()} API
      * provided by JetPack.
@@ -289,12 +413,24 @@
      * 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}.
+     * @throws RuntimeException If an error occurred during the execution.
+     *
+     * @deprecated use {@link AppSearchSession#removeByUri} instead.
      */
     public AppSearchBatchResult<String, Void> removeByUri(@NonNull RemoveByUriRequest request) {
         List<String> uris = new ArrayList<>(request.getUris());
         AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
         try {
-            mService.removeByUri(DEFAULT_DATABASE, request.getNamespace(), uris, future);
+            mService.removeByUri(DEFAULT_DATABASE_NAME, request.getNamespace(), uris,
+                    new IAppSearchBatchResultCallback.Stub() {
+                        public void onResult(AppSearchBatchResult result) {
+                            future.complete(result);
+                        }
+
+                        public void onSystemError(ParcelableException exception) {
+                            future.completeExceptionally(exception);
+                        }
+                    });
         } catch (RemoteException e) {
             future.completeExceptionally(e);
         }
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
similarity index 80%
copy from location/java/android/location/timezone/LocationTimeZoneEvent.aidl
copy to apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
index 5386588..f0b2996 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
@@ -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,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.app.appsearch;
 
-package android.location.timezone;
-
-parcelable LocationTimeZoneEvent;
+/** {@hide} */
+parcelable AppSearchResult;
\ No newline at end of file
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
index 979eab9..6e2ed70 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
@@ -19,9 +19,11 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.appsearch.exceptions.AppSearchException;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
@@ -218,4 +220,25 @@
             @ResultCode int resultCode, @Nullable String errorMessage) {
         return new AppSearchResult<>(resultCode, /*resultValue=*/ null, errorMessage);
     }
+
+    /** @hide */
+    @NonNull
+    public static <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
+            @NonNull Throwable t) {
+        if (t instanceof AppSearchException) {
+            return ((AppSearchException) t).toAppSearchResult();
+        }
+
+        @AppSearchResult.ResultCode int resultCode;
+        if (t instanceof IllegalStateException) {
+            resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
+        } else if (t instanceof IllegalArgumentException) {
+            resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
+        } else if (t instanceof IOException) {
+            resultCode = AppSearchResult.RESULT_IO_ERROR;
+        } else {
+            resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
+        }
+        return AppSearchResult.newFailedResult(resultCode, t.toString());
+    }
 }
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
new file mode 100644
index 0000000..fd4b106
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.os.Bundle;
+import android.os.ParcelableException;
+import android.os.RemoteException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Represents a connection to an AppSearch storage system where {@link GenericDocument}s can be
+ * placed and queried.
+ * @hide
+ */
+public final class AppSearchSession {
+    private final String mDatabaseName;
+    private final IAppSearchManager mService;
+
+    static void createSearchSession(
+            @NonNull AppSearchManager.SearchContext searchContext,
+            @NonNull IAppSearchManager service,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
+        AppSearchSession searchSession =
+                new AppSearchSession(searchContext.mDatabaseName, service);
+        searchSession.initialize(executor, callback);
+    }
+
+    // NOTE: No instance of this class should be created or returned except via initialize().
+    // Once the callback.accept has been called here, the class is ready to use.
+    private void initialize(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
+        try {
+            mService.initialize(new IAppSearchResultCallback.Stub() {
+                public void onResult(AppSearchResult result) {
+                    executor.execute(() -> {
+                        if (result.isSuccess()) {
+                            callback.accept(
+                                    AppSearchResult.newSuccessfulResult(AppSearchSession.this));
+                        } else {
+                            callback.accept(result);
+                        }
+                    });
+                }
+            });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private AppSearchSession(@NonNull String databaseName, @NonNull IAppSearchManager service) {
+        mDatabaseName = databaseName;
+        mService = service;
+    }
+
+    /**
+     * Sets the schema will be used by documents provided to the {@link #putDocuments} method.
+     *
+     * <p>The schema provided here is compared to the stored copy of the schema previously supplied
+     * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
+     * types of schema modifications are always safe and are made without deleting any existing
+     * documents:
+     * <ul>
+     *     <li>Addition of new types
+     *     <li>Addition of new
+     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
+     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
+     *         type
+     *     <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
+     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
+     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
+     * </ul>
+     *
+     * <p>The following types of schema changes are not backwards-compatible:
+     * <ul>
+     *     <li>Removal of an existing type
+     *     <li>Removal of a property from a type
+     *     <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
+     *     <li>For properties of {@code Document} type, changing the schema type of
+     *         {@code Document}s of that property
+     *     <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
+     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
+     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
+     *     <li>Adding a
+     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
+     * </ul>
+     * <p>Supplying a schema with such changes will, by default, result in this call returning an
+     * {@link AppSearchResult} with a code of {@link AppSearchResult#RESULT_INVALID_SCHEMA} and an
+     * error 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 returning an {@link AppSearchResult} 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.
+     *
+     * @param request The schema update request.
+     * @param executor Executor on which to invoke the callback.
+     * @param callback Callback to receive errors resulting from setting the schema. If the
+     *                 operation succeeds, the callback will be invoked with {@code null}.
+     */
+    public void setSchema(
+            @NonNull SetSchemaRequest request,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<Void>> callback) {
+        Objects.requireNonNull(request);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        List<Bundle> schemaBundles = new ArrayList<>(request.getSchemas().size());
+        for (AppSearchSchema schema : request.getSchemas()) {
+            schemaBundles.add(schema.getBundle());
+        }
+        try {
+            mService.setSchema(mDatabaseName, schemaBundles, request.isForceOverride(),
+                    new IAppSearchResultCallback.Stub() {
+                        public void onResult(AppSearchResult result) {
+                            executor.execute(() -> callback.accept(result));
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indexes documents into AppSearch.
+     *
+     * <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a
+     * schema type previously registered via the {@link #setSchema} method.
+     *
+     * @param request  {@link PutDocumentsRequest} containing documents to be indexed
+     * @param executor Executor on which to invoke the callback.
+     * @param callback Callback to receive pending result of performing this operation. The keys
+     *                 of the returned {@link AppSearchBatchResult} are the URIs of the input
+     *                 documents. The values are {@code null} if they were successfully indexed,
+     *                 or a failed {@link AppSearchResult} otherwise.
+     *                 Or {@link BatchResultCallback#onSystemError} will be invoked with an
+     *                 {@link AppSearchException} if an error occurred in AppSearch initialization
+     *                 or a cause {@link Throwable} if other error occurred in AppSearch service.
+     */
+    public void putDocuments(
+            @NonNull PutDocumentsRequest request,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BatchResultCallback<String, Void> callback) {
+        Objects.requireNonNull(request);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        List<GenericDocument> documents = request.getDocuments();
+        List<Bundle> documentBundles = new ArrayList<>(documents.size());
+        for (int i = 0; i < documents.size(); i++) {
+            documentBundles.add(documents.get(i).getBundle());
+        }
+        try {
+            mService.putDocuments(mDatabaseName, documentBundles,
+                    new IAppSearchBatchResultCallback.Stub() {
+                        public void onResult(AppSearchBatchResult result) {
+                            executor.execute(() -> callback.onResult(result));
+                        }
+
+                        public void onSystemError(ParcelableException exception) {
+                            executor.execute(() -> callback.onSystemError(exception.getCause()));
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieves {@link GenericDocument}s by URI.
+     *
+     * @param request {@link GetByUriRequest} containing URIs to be retrieved.
+     * @param executor Executor on which to invoke the callback.
+     * @param callback Callback to receive 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}.
+     *                 Or {@link BatchResultCallback#onSystemError} will be invoked with an
+     *                 {@link AppSearchException} if an error occurred in AppSearch initialization
+     *                 or a cause {@link Throwable} if other error occurred in AppSearch service.
+     */
+    public void getByUri(
+            @NonNull GetByUriRequest request,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BatchResultCallback<String, GenericDocument> callback) {
+        Objects.requireNonNull(request);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        try {
+            mService.getDocuments(mDatabaseName, request.getNamespace(),
+                    new ArrayList<>(request.getUris()),
+                    new IAppSearchBatchResultCallback.Stub() {
+                        public void onResult(AppSearchBatchResult result) {
+                            executor.execute(() -> {
+                                AppSearchBatchResult.Builder<String, GenericDocument>
+                                        documentResultBuilder =
+                                        new AppSearchBatchResult.Builder<>();
+
+                                // Translate successful results
+                                for (Map.Entry<String, Bundle> bundleEntry :
+                                        (Set<Map.Entry<String, Bundle>>)
+                                                result.getSuccesses().entrySet()) {
+                                    GenericDocument document;
+                                    try {
+                                        document = new GenericDocument(bundleEntry.getValue());
+                                    } catch (Throwable t) {
+                                        // These documents went through validation, so how could
+                                        // this fail? We must have done something wrong.
+                                        documentResultBuilder.setFailure(
+                                                bundleEntry.getKey(),
+                                                AppSearchResult.RESULT_INTERNAL_ERROR,
+                                                t.getMessage());
+                                        continue;
+                                    }
+                                    documentResultBuilder.setSuccess(
+                                            bundleEntry.getKey(), document);
+                                }
+
+                                // Translate failed results
+                                for (Map.Entry<String, AppSearchResult<Bundle>> bundleEntry :
+                                        (Set<Map.Entry<String, AppSearchResult<Bundle>>>)
+                                                result.getFailures().entrySet()) {
+                                    documentResultBuilder.setFailure(
+                                            bundleEntry.getKey(),
+                                            bundleEntry.getValue().getResultCode(),
+                                            bundleEntry.getValue().getErrorMessage());
+                                }
+                                callback.onResult(documentResultBuilder.build());
+                            });
+                        }
+
+                        public void onSystemError(ParcelableException exception) {
+                            executor.execute(() -> callback.onSystemError(exception.getCause()));
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Removes {@link GenericDocument}s from the index by URI.
+     *
+     * @param request Request containing URIs to be removed.
+     * @param executor Executor on which to invoke the callback.
+     * @param callback Callback to receive 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}.
+     *                 Or {@link BatchResultCallback#onSystemError} will be invoked with an
+     *                 {@link AppSearchException} if an error occurred in AppSearch initialization
+     *                 or a cause {@link Throwable} if other error occurred in AppSearch service.
+     */
+    public void removeByUri(
+            @NonNull RemoveByUriRequest request,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BatchResultCallback<String, Void> callback) {
+        Objects.requireNonNull(request);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        try {
+            mService.removeByUri(mDatabaseName, request.getNamespace(),
+                    new ArrayList<>(request.getUris()),
+                    new IAppSearchBatchResultCallback.Stub() {
+                        public void onResult(AppSearchBatchResult result) {
+                            executor.execute(() -> callback.onResult(result));
+                        }
+
+                        public void onSystemError(ParcelableException exception) {
+                            executor.execute(() -> callback.onSystemError(exception.getCause()));
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * 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#addSchema}.
+     *
+     * <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.
+     *
+     * @param queryExpression Query String to search.
+     * @param searchSpec Defines what and how to remove
+     * @param executor Executor on which to invoke the callback.
+     * @param callback Callback to receive errors resulting from removing the documents. If the
+     *                 operation succeeds, the callback will be invoked with {@code null}.
+     */
+    public void removeByQuery(@NonNull String queryExpression,
+            @NonNull SearchSpec searchSpec,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<Void>> callback) {
+        Objects.requireNonNull(queryExpression);
+        Objects.requireNonNull(searchSpec);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        try {
+            mService.removeByQuery(mDatabaseName, queryExpression, searchSpec.getBundle(),
+                    new IAppSearchResultCallback.Stub() {
+                        public void onResult(AppSearchResult result) {
+                            executor.execute(() -> callback.accept(result));
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    // TODO(b/162450968) port query() and SearchResults.java to platform.
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/BatchResultCallback.java b/apex/appsearch/framework/java/android/app/appsearch/BatchResultCallback.java
new file mode 100644
index 0000000..1689e02
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/BatchResultCallback.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch;
+
+/**
+ * The callback interface to return {@link AppSearchBatchResult}.
+ *
+ * @param <KeyType> The type of the keys for {@link AppSearchBatchResult#getSuccesses} and
+ * {@link AppSearchBatchResult#getFailures}.
+ * @param <ValueType> The type of result objects associated with the keys.
+ * @hide
+ */
+public interface BatchResultCallback<KeyType, ValueType> {
+
+    /**
+     * Called when {@link AppSearchBatchResult} results are ready.
+     *
+     * @param result The result of the executed request.
+     */
+    void onResult(AppSearchBatchResult<KeyType, ValueType> result);
+
+
+    /**
+     * Called when a system error occurred.
+     *
+     * @param throwable The cause throwable.
+     */
+    default void onSystemError(Throwable throwable) {
+        if (throwable != null) {
+            throw new RuntimeException(throwable);
+        }
+    }
+}
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
similarity index 61%
copy from location/java/android/location/timezone/LocationTimeZoneEvent.aidl
copy to apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
index 5386588..b1bbd18 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
@@ -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,7 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.app.appsearch;
 
-package android.location.timezone;
+import android.app.appsearch.AppSearchBatchResult;
+import android.os.ParcelableException;
 
-parcelable LocationTimeZoneEvent;
+/** {@hide} */
+oneway interface IAppSearchBatchResultCallback {
+    void onResult(in AppSearchBatchResult result);
+    void onSystemError(in ParcelableException exception);
+}
\ No newline at end of file
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 01260ea..62e60d7 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -17,10 +17,12 @@
 
 import android.os.Bundle;
 
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.IAppSearchBatchResultCallback;
+import android.app.appsearch.IAppSearchResultCallback;
 import com.android.internal.infra.AndroidFuture;
 
-parcelable AppSearchResult;
-parcelable AppSearchBatchResult;
 parcelable SearchResults;
 
 /** {@hide} */
@@ -32,14 +34,14 @@
      * @param schemaBundles List of AppSearchSchema bundles.
      * @param forceOverride Whether to apply the new schema even if it is incompatible. All
      *     incompatible documents will be deleted.
-     * @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link Void}&gt&gt;.
-     *     The results of the call.
+     * @param callback {@link IAppSearchResultCallback#onResult} will be called with an
+     *     {@link AppSearchResult}&lt;{@link Void}&gt;.
      */
     void setSchema(
         in String databaseName,
         in List<Bundle> schemaBundles,
         boolean forceOverride,
-        in AndroidFuture<AppSearchResult> callback);
+        in IAppSearchResultCallback callback);
 
     /**
      * Inserts documents into the index.
@@ -47,16 +49,16 @@
      * @param databaseName  The name of the database where this document lives.
      * @param documentBundes List of GenericDocument bundles.
      * @param callback
-     *     {@link AndroidFuture}&lt;{@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;&gt;.
-     *     If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
-     *     {@code callback} will be completed with an
+     *     If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
+     *     will be called with the cause throwable. Otherwise,
+     *     {@link IAppSearchBatchResultCallback#onResult} will be called with an
      *     {@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;
      *     where the keys are document URIs, and the values are {@code null}.
      */
     void putDocuments(
         in String databaseName,
         in List<Bundle> documentBundles,
-        in AndroidFuture<AppSearchBatchResult> callback);
+        in IAppSearchBatchResultCallback callback);
 
     /**
      * Retrieves documents from the index.
@@ -65,9 +67,9 @@
      * @param namespace    The namespace this document resides in.
      * @param uris The URIs of the documents to retrieve
      * @param callback
-     *     {@link AndroidFuture}&lt;{@link AppSearchBatchResult}&lt;{@link String}, {@link Bundle}&gt;&gt;.
-     *     If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
-     *     {@code callback} will be completed with an
+     *     If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
+     *     will be called with the cause throwable. Otherwise,
+     *     {@link IAppSearchBatchResultCallback#onResult} will be called with an
      *     {@link AppSearchBatchResult}&lt;{@link String}, {@link Bundle}&gt;
      *     where the keys are document URIs, and the values are Document bundles.
      */
@@ -75,7 +77,7 @@
         in String databaseName,
         in String namespace,
         in List<String> uris,
-        in AndroidFuture<AppSearchBatchResult> callback);
+        in IAppSearchBatchResultCallback callback);
 
     /**
      * Searches a document based on a given specifications.
@@ -98,9 +100,9 @@
      * @param namespace    Namespace of the document to remove.
      * @param uris The URIs of the documents to delete
      * @param callback
-     *     {@link AndroidFuture}&lt;{@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;&gt;.
-     *     If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
-     *     {@code callback} will be completed with an
+     *     If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
+     *     will be called with the cause throwable. Otherwise,
+     *     {@link IAppSearchBatchResultCallback#onResult} will be called with an
      *     {@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;
      *     where the keys are document URIs. If a document doesn't exist, it will be reported as a
      *     failure where the {@code throwable} is {@code null}.
@@ -109,7 +111,7 @@
         in String databaseName,
         in String namespace,
         in List<String> uris,
-        in AndroidFuture<AppSearchBatchResult> callback);
+        in IAppSearchBatchResultCallback callback);
 
     /**
      * Removes documents by given query.
@@ -117,11 +119,20 @@
      * @param databaseName The databaseName this query for.
      * @param queryExpression String to search for
      * @param searchSpecBundle SearchSpec bundle
-     * @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link SearchResults}&gt;&gt;
+     * @param callback {@link IAppSearchResultCallback#onResult} will be called with an
+     *     {@link AppSearchResult}&lt;{@link Void}&gt;.
      */
     void removeByQuery(
         in String databaseName,
         in String queryExpression,
         in Bundle searchSpecBundle,
-        in AndroidFuture<AppSearchResult> callback);
+        in IAppSearchResultCallback callback);
+
+    /**
+     * Creates and initializes AppSearchImpl for the calling app.
+     *
+     * @param callback {@link IAppSearchResultCallback#onResult} will be called with an
+     *     {@link AppSearchResult}&lt;{@link Void}&gt;.
+     */
+    void initialize(in IAppSearchResultCallback callback);
 }
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
similarity index 66%
copy from location/java/android/location/timezone/LocationTimeZoneEvent.aidl
copy to apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
index 5386588..27729a5 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
@@ -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,7 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.app.appsearch;
 
-package android.location.timezone;
+import android.app.appsearch.AppSearchResult;
+import android.os.ParcelableException;
 
-parcelable LocationTimeZoneEvent;
+/** {@hide} */
+oneway interface IAppSearchResultCallback {
+    void onResult(in AppSearchResult result);
+}
\ No newline at end of file
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 1dfde52..c9dd89c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -15,27 +15,32 @@
  */
 package com.android.server.appsearch;
 
+import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
+
 import android.annotation.NonNull;
 import android.app.appsearch.AppSearchBatchResult;
 import android.app.appsearch.AppSearchResult;
 import android.app.appsearch.AppSearchSchema;
 import android.app.appsearch.GenericDocument;
+import android.app.appsearch.IAppSearchBatchResultCallback;
 import android.app.appsearch.IAppSearchManager;
+import android.app.appsearch.IAppSearchResultCallback;
 import android.app.appsearch.SearchResultPage;
 import android.app.appsearch.SearchSpec;
-import android.app.appsearch.exceptions.AppSearchException;
 import android.content.Context;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.ParcelableException;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 import com.android.server.appsearch.external.localstorage.AppSearchImpl;
 
-import java.io.IOException;
 import java.util.List;
 import java.util.Set;
 
@@ -61,10 +66,9 @@
                 @NonNull String databaseName,
                 @NonNull List<Bundle> schemaBundles,
                 boolean forceOverride,
-                @NonNull AndroidFuture<AppSearchResult> callback) {
+                @NonNull IAppSearchResultCallback callback) {
             Preconditions.checkNotNull(databaseName);
             Preconditions.checkNotNull(schemaBundles);
-            Preconditions.checkNotNull(callback);
             int callingUid = Binder.getCallingUidOrThrow();
             int callingUserId = UserHandle.getUserId(callingUid);
             final long callingIdentity = Binder.clearCallingIdentity();
@@ -76,9 +80,10 @@
                 AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                 databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                 impl.setSchema(databaseName, schemas, forceOverride);
-                callback.complete(AppSearchResult.newSuccessfulResult(/*result=*/ null));
+                invokeCallbackOnResult(callback,
+                        AppSearchResult.newSuccessfulResult(/*result=*/ null));
             } catch (Throwable t) {
-                callback.complete(throwableToFailedResult(t));
+                invokeCallbackOnError(callback, t);
             } finally {
                 Binder.restoreCallingIdentity(callingIdentity);
             }
@@ -88,7 +93,7 @@
         public void putDocuments(
                 @NonNull String databaseName,
                 @NonNull List<Bundle> documentBundles,
-                @NonNull AndroidFuture<AppSearchBatchResult> callback) {
+                @NonNull IAppSearchBatchResultCallback callback) {
             Preconditions.checkNotNull(databaseName);
             Preconditions.checkNotNull(documentBundles);
             Preconditions.checkNotNull(callback);
@@ -96,22 +101,24 @@
             int callingUserId = UserHandle.getUserId(callingUid);
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
-                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
-                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                 AppSearchBatchResult.Builder<String, Void> resultBuilder =
                         new AppSearchBatchResult.Builder<>();
+                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                 for (int i = 0; i < documentBundles.size(); i++) {
                     GenericDocument document = new GenericDocument(documentBundles.get(i));
                     try {
+                        // TODO(b/173451571): reduce burden of binder thread by enqueue request onto
+                        // a separate thread.
                         impl.putDocument(databaseName, document);
                         resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
                     } catch (Throwable t) {
                         resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
                     }
                 }
-                callback.complete(resultBuilder.build());
+                invokeCallbackOnResult(callback, resultBuilder.build());
             } catch (Throwable t) {
-                callback.completeExceptionally(t);
+                invokeCallbackOnError(callback, t);
             } finally {
                 Binder.restoreCallingIdentity(callingIdentity);
             }
@@ -119,7 +126,8 @@
 
         @Override
         public void getDocuments(@NonNull String databaseName, @NonNull String namespace,
-                @NonNull List<String> uris, @NonNull AndroidFuture<AppSearchBatchResult> callback) {
+                @NonNull List<String> uris,
+                @NonNull IAppSearchBatchResultCallback callback) {
             Preconditions.checkNotNull(databaseName);
             Preconditions.checkNotNull(namespace);
             Preconditions.checkNotNull(uris);
@@ -128,10 +136,10 @@
             int callingUserId = UserHandle.getUserId(callingUid);
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
-                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
-                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                 AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
                         new AppSearchBatchResult.Builder<>();
+                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                 for (int i = 0; i < uris.size(); i++) {
                     String uri = uris.get(i);
                     try {
@@ -141,9 +149,9 @@
                         resultBuilder.setResult(uri, throwableToFailedResult(t));
                     }
                 }
-                callback.complete(resultBuilder.build());
+                invokeCallbackOnResult(callback, resultBuilder.build());
             } catch (Throwable t) {
-                callback.completeExceptionally(t);
+                invokeCallbackOnError(callback, t);
             } finally {
                 Binder.restoreCallingIdentity(callingIdentity);
             }
@@ -182,19 +190,19 @@
 
         @Override
         public void removeByUri(@NonNull String databaseName, @NonNull String namespace,
-                List<String> uris, AndroidFuture<AppSearchBatchResult> callback) {
+                @NonNull List<String> uris,
+                @NonNull IAppSearchBatchResultCallback callback) {
             Preconditions.checkNotNull(databaseName);
-            Preconditions.checkNotNull(namespace);
             Preconditions.checkNotNull(uris);
             Preconditions.checkNotNull(callback);
             int callingUid = Binder.getCallingUidOrThrow();
             int callingUserId = UserHandle.getUserId(callingUid);
             final long callingIdentity = Binder.clearCallingIdentity();
+            AppSearchBatchResult.Builder<String, Void> resultBuilder =
+                    new AppSearchBatchResult.Builder<>();
             try {
                 AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                 databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
-                AppSearchBatchResult.Builder<String, Void> resultBuilder =
-                        new AppSearchBatchResult.Builder<>();
                 for (int i = 0; i < uris.size(); i++) {
                     String uri = uris.get(i);
                     try {
@@ -204,9 +212,9 @@
                         resultBuilder.setResult(uri, throwableToFailedResult(t));
                     }
                 }
-                callback.complete(resultBuilder.build());
+                invokeCallbackOnResult(callback, resultBuilder.build());
             } catch (Throwable t) {
-                callback.completeExceptionally(t);
+                invokeCallbackOnError(callback, t);
             } finally {
                 Binder.restoreCallingIdentity(callingIdentity);
             }
@@ -217,21 +225,36 @@
                 @NonNull String databaseName,
                 @NonNull String queryExpression,
                 @NonNull Bundle searchSpecBundle,
-                @NonNull AndroidFuture<AppSearchResult> callback) {
+                @NonNull IAppSearchResultCallback callback) {
             Preconditions.checkNotNull(databaseName);
             Preconditions.checkNotNull(queryExpression);
             Preconditions.checkNotNull(searchSpecBundle);
-            Preconditions.checkNotNull(callback);
             int callingUid = Binder.getCallingUidOrThrow();
             int callingUserId = UserHandle.getUserId(callingUid);
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
                 AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                 databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
-                impl.removeByQuery(databaseName, queryExpression, new SearchSpec(searchSpecBundle));
-                callback.complete(AppSearchResult.newSuccessfulResult(/*result= */null));
+                impl.removeByQuery(databaseName, queryExpression,
+                        new SearchSpec(searchSpecBundle));
+                invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
             } catch (Throwable t) {
-                callback.complete(throwableToFailedResult(t));
+                invokeCallbackOnError(callback, t);
+            } finally {
+                Binder.restoreCallingIdentity(callingIdentity);
+            }
+        }
+
+        @Override
+        public void initialize(@NonNull IAppSearchResultCallback callback) {
+            int callingUid = Binder.getCallingUidOrThrow();
+            int callingUserId = UserHandle.getUserId(callingUid);
+            final long callingIdentity = Binder.clearCallingIdentity();
+            try {
+                ImplInstanceManager.getInstance(getContext(), callingUserId);
+                invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
+            } catch (Throwable t) {
+                invokeCallbackOnError(callback, t);
             } finally {
                 Binder.restoreCallingIdentity(callingIdentity);
             }
@@ -256,23 +279,51 @@
             return callingUidName + CALLING_NAME_DATABASE_DELIMITER + databaseName;
         }
 
-        private <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
-                @NonNull Throwable t) {
-            if (t instanceof AppSearchException) {
-                return ((AppSearchException) t).toAppSearchResult();
+        /**  Invokes the {@link IAppSearchResultCallback} with the result. */
+        private void invokeCallbackOnResult(IAppSearchResultCallback callback,
+                AppSearchResult result) {
+            try {
+                callback.onResult(result);
+            } catch (RemoteException e) {
+                Log.d(TAG, "Unable to send result to the callback", e);
             }
+        }
 
-            @AppSearchResult.ResultCode int resultCode;
-            if (t instanceof IllegalStateException) {
-                resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
-            } else if (t instanceof IllegalArgumentException) {
-                resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
-            } else if (t instanceof IOException) {
-                resultCode = AppSearchResult.RESULT_IO_ERROR;
-            } else {
-                resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
+        /**  Invokes the {@link IAppSearchBatchResultCallback} with the result. */
+        private void invokeCallbackOnResult(IAppSearchBatchResultCallback callback,
+                AppSearchBatchResult result) {
+            try {
+                callback.onResult(result);
+            } catch (RemoteException e) {
+                Log.d(TAG, "Unable to send result to the callback", e);
             }
-            return AppSearchResult.newFailedResult(resultCode, t.getMessage());
+        }
+
+        /**
+         *  Invokes the {@link IAppSearchResultCallback} with an throwable.
+         *
+         *  <p>The throwable is convert to a {@link AppSearchResult};
+         */
+        private void invokeCallbackOnError(IAppSearchResultCallback callback, Throwable throwable) {
+            try {
+                callback.onResult(throwableToFailedResult(throwable));
+            } catch (RemoteException e) {
+                Log.d(TAG, "Unable to send result to the callback", e);
+            }
+        }
+
+        /**
+         *  Invokes the {@link IAppSearchBatchResultCallback} with an throwable.
+         *
+         * <p>The throwable is converted to {@link ParcelableException}.
+         */
+        private void invokeCallbackOnError(IAppSearchBatchResultCallback callback,
+                Throwable throwable) {
+            try {
+                callback.onSystemError(new ParcelableException(throwable));
+            } catch (RemoteException e) {
+                Log.d(TAG, "Unable to send error to the callback", e);
+            }
         }
     }
 }
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 2c8a558..3597c27 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -462,11 +462,11 @@
     public @NetworkType int getNetworkType() {
         if (networkRequest == null) {
             return NETWORK_TYPE_NONE;
-        } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+        } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_METERED)) {
             return NETWORK_TYPE_UNMETERED;
-        } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
+        } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
             return NETWORK_TYPE_NOT_ROAMING;
-        } else if (networkRequest.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+        } else if (networkRequest.hasTransport(TRANSPORT_CELLULAR)) {
             return NETWORK_TYPE_CELLULAR;
         } else {
             return NETWORK_TYPE_ANY;
@@ -1558,7 +1558,7 @@
         if (isPersisted) {
             // We can't serialize network specifiers
             if (networkRequest != null
-                    && networkRequest.networkCapabilities.getNetworkSpecifier() != null) {
+                    && networkRequest.getNetworkSpecifier() != null) {
                 throw new IllegalArgumentException(
                         "Network specifiers aren't supported for persistent jobs");
             }
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 398ccb6..2ce85ee 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -3,7 +3,6 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.usage.AppStandbyInfo;
-import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
 import android.app.usage.UsageStatsManager.SystemForcedReasons;
 import android.content.Context;
@@ -68,8 +67,6 @@
      */
     void postOneTimeCheckIdleStates();
 
-    void reportEvent(UsageEvents.Event event, int userId);
-
     void setLastJobRunTime(String packageName, int userId, long elapsedRealtime);
 
     long getTimeSinceLastJobRun(String packageName, int userId);
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index d4ea7af..20c77da 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -417,6 +417,9 @@
         @VisibleForTesting
         static final String KEY_LAZY_BATCHING = "lazy_batching";
 
+        private static final String KEY_TIME_TICK_ALLOWED_WHILE_IDLE =
+                "time_tick_allowed_while_idle";
+
         private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
         private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
         private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -440,6 +443,7 @@
         private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = MILLIS_IN_DAY;
 
         private static final boolean DEFAULT_LAZY_BATCHING = true;
+        private static final boolean DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE = true;
 
         // Minimum futurity of a new alarm
         public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -470,6 +474,7 @@
         public long APP_STANDBY_RESTRICTED_WINDOW = DEFAULT_APP_STANDBY_RESTRICTED_WINDOW;
 
         public boolean LAZY_BATCHING = DEFAULT_LAZY_BATCHING;
+        public boolean TIME_TICK_ALLOWED_WHILE_IDLE = DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE;
 
         private long mLastAllowWhileIdleWhitelistDuration = -1;
 
@@ -557,6 +562,11 @@
                                 migrateAlarmsToNewStoreLocked();
                             }
                             break;
+                        case KEY_TIME_TICK_ALLOWED_WHILE_IDLE:
+                            TIME_TICK_ALLOWED_WHILE_IDLE = properties.getBoolean(
+                                    KEY_TIME_TICK_ALLOWED_WHILE_IDLE,
+                                    DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE);
+                            break;
                         default:
                             if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
                                 // The quotas need to be updated in order, so we can't just rely
@@ -690,6 +700,9 @@
             pw.print(KEY_LAZY_BATCHING, LAZY_BATCHING);
             pw.println();
 
+            pw.print(KEY_TIME_TICK_ALLOWED_WHILE_IDLE, TIME_TICK_ALLOWED_WHILE_IDLE);
+            pw.println();
+
             pw.decreaseIndent();
         }
 
@@ -3756,9 +3769,14 @@
             final long tickEventDelay = nextTime - currentTime;
 
             final WorkSource workSource = null; // Let system take blame for time tick events.
+
+            int flags = AlarmManager.FLAG_STANDALONE;
+            flags |= mConstants.TIME_TICK_ALLOWED_WHILE_IDLE ? FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
+                    : 0;
+
             setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
-                    0, null, mTimeTickTrigger, TIME_TICK_TAG, AlarmManager.FLAG_STANDALONE,
-                    workSource, null, Process.myUid(), "android");
+                    0, null, mTimeTickTrigger, TIME_TICK_TAG, flags, workSource, null,
+                    Process.myUid(), "android");
 
             // Finally, remember when we set the tick alarm
             synchronized (mLock) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index 56b97f2..2b5aab8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
@@ -282,12 +282,13 @@
             String nextDelayPackageName = null;
             boolean ready = false;
             Iterator<JobStatus> it = mTrackedJobs.iterator();
+            final long nowElapsedMillis = sElapsedRealtimeClock.millis();
             while (it.hasNext()) {
                 final JobStatus job = it.next();
                 if (!job.hasTimingDelayConstraint()) {
                     continue;
                 }
-                if (evaluateTimingDelayConstraint(job, sElapsedRealtimeClock.millis())) {
+                if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
                     if (canStopTrackingJobLocked(job)) {
                         it.remove();
                     }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 1157ee9..0b0923a 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -62,6 +62,7 @@
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
 import android.app.usage.UsageStatsManager.SystemForcedReasons;
+import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -128,9 +129,10 @@
  * Manages the standby state of an app, listening to various events.
  *
  * Unit test:
-   atest com.android.server.usage.AppStandbyControllerTests
+ * atest com.android.server.usage.AppStandbyControllerTests
  */
-public class AppStandbyController implements AppStandbyInternal {
+public class AppStandbyController
+        implements AppStandbyInternal, UsageStatsManagerInternal.UsageEventListener {
 
     private static final String TAG = "AppStandbyController";
     // Do not submit with true.
@@ -468,10 +470,21 @@
 
     @VisibleForTesting
     void setAppIdleEnabled(boolean enabled) {
+        // Don't call out to USM with the lock held. Also, register the listener before we
+        // change our internal state so no events fall through the cracks.
+        final UsageStatsManagerInternal usmi =
+                LocalServices.getService(UsageStatsManagerInternal.class);
+        if (enabled) {
+            usmi.registerListener(this);
+        } else {
+            usmi.unregisterListener(this);
+        }
+
         synchronized (mAppIdleLock) {
             if (mAppIdleEnabled != enabled) {
                 final boolean oldParoleState = isInParole();
                 mAppIdleEnabled = enabled;
+
                 if (isInParole() != oldParoleState) {
                     postParoleStateChanged();
                 }
@@ -489,6 +502,11 @@
         mInjector.onBootPhase(phase);
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             Slog.d(TAG, "Setting app idle enabled state");
+
+            if (mAppIdleEnabled) {
+                LocalServices.getService(UsageStatsManagerInternal.class).registerListener(this);
+            }
+
             // Observe changes to the threshold
             ConstantsObserver settingsObserver = new ConstantsObserver(mHandler);
             settingsObserver.start();
@@ -912,8 +930,10 @@
         }
     }
 
-    @Override
-    public void reportEvent(UsageEvents.Event event, int userId) {
+    /**
+     * Callback to inform listeners of a new event.
+     */
+    public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
         if (!mAppIdleEnabled) return;
         final int eventType = event.getEventType();
         if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 046145f..3b4823e 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -605,6 +605,7 @@
         result = movie();
     }
 
+    mCallbacks->shutdown();
     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglDestroyContext(mDisplay, mContext);
     eglDestroySurface(mDisplay, mSurface);
@@ -691,7 +692,6 @@
     int exitnow = atoi(value);
     if (exitnow) {
         requestExit();
-        mCallbacks->shutdown();
     }
 }
 
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index c2ee6dc..ef1e413 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -101,8 +101,6 @@
             runFstrim();
         } else if ("set-virtual-disk".equals(op)) {
             runSetVirtualDisk();
-        } else if ("set-isolated-storage".equals(op)) {
-            runIsolatedStorage();
         } else if ("start-checkpoint".equals(op)) {
             runStartCheckpoint();
         } else if ("supports-checkpoint".equals(op)) {
@@ -286,28 +284,6 @@
                 StorageManager.DEBUG_VIRTUAL_DISK);
     }
 
-    public void runIsolatedStorage() throws RemoteException {
-        final int value;
-        final int mask = StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON
-                | StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF;
-        switch (nextArg()) {
-            case "on":
-            case "true":
-                value = StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON;
-                break;
-            case "off":
-                value = StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF;
-                break;
-            case "default":
-            case "false":
-                value = 0;
-                break;
-            default:
-                return;
-        }
-        mSm.setDebugFlags(value, mask);
-    }
-
     public void runIdleMaint() throws RemoteException {
         final boolean im_run = "run".equals(nextArg());
         if (im_run) {
@@ -367,8 +343,6 @@
         System.err.println("");
         System.err.println("       sm set-emulate-fbe [true|false]");
         System.err.println("");
-        System.err.println("       sm set-isolated-storage [on|off|default]");
-        System.err.println("");
         System.err.println("       sm start-checkpoint <num-retries>");
         System.err.println("");
         System.err.println("       sm supports-checkpoint");
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index d225f966..6aad82f 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -14,34 +14,6 @@
 // limitations under the License.
 //
 
-// ==========================================================
-// Build the library for use on the host
-// ==========================================================
-cc_library_host_shared {
-    name: "libstats_proto_host",
-    srcs: [
-        "src/atoms.proto",
-        "src/atom_field_options.proto",
-    ],
-
-    shared_libs: [
-        "libplatformprotos",
-    ],
-
-    proto: {
-        type: "full",
-        export_proto_headers: true,
-        include_dirs: [
-            "external/protobuf/src",
-        ],
-    },
-
-    export_shared_lib_headers: [
-        "libplatformprotos",
-    ]
-
-}
-
 cc_defaults {
     name: "statsd_defaults",
 
@@ -277,9 +249,8 @@
         // atom_field_options.proto needs field_options.proto, but that is
         // not included in libprotobuf-cpp-lite, so compile it here.
         ":libprotobuf-internal-protos",
+        ":libstats_internal_protos",
 
-        "src/atom_field_options.proto",
-        "src/atoms.proto",
         "src/shell/shell_data.proto",
         "src/stats_log.proto",
         "tests/AlarmMonitor_test.cpp",
@@ -346,7 +317,10 @@
 
     proto: {
         type: "lite",
-        include_dirs: ["external/protobuf/src"],
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
     },
 
 }
@@ -363,6 +337,7 @@
         // atom_field_options.proto needs field_options.proto, but that is
         // not included in libprotobuf-cpp-lite, so compile it here.
         ":libprotobuf-internal-protos",
+        ":libstats_internal_protos",
 
         "benchmark/duration_metric_benchmark.cpp",
         "benchmark/filter_value_benchmark.cpp",
@@ -372,14 +347,15 @@
         "benchmark/main.cpp",
         "benchmark/metric_util.cpp",
         "benchmark/stats_write_benchmark.cpp",
-        "src/atom_field_options.proto",
-        "src/atoms.proto",
         "src/stats_log.proto",
     ],
 
     proto: {
         type: "lite",
-        include_dirs: ["external/protobuf/src"],
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
     },
 
     cflags: [
@@ -411,11 +387,14 @@
     sdk_version: "core_current",
     proto: {
         type: "lite",
-        include_dirs: ["external/protobuf/src"],
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
     },
 
     srcs: [
-        "src/atoms.proto",
+        ":libstats_atoms_proto",
         "src/shell/shell_config.proto",
         "src/shell/shell_data.proto",
         "src/stats_log.proto",
@@ -437,10 +416,13 @@
     proto: {
         type: "nano",
         output_params: ["store_unknown_fields=true"],
-        include_dirs: ["external/protobuf/src"],
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
     },
     srcs: [
-        "src/atoms.proto",
+        ":libstats_atoms_proto",
         "src/shell/shell_config.proto",
         "src/shell/shell_data.proto",
         "src/stats_log.proto",
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
index a61babf..4e4e119 100644
--- a/cmds/statsd/OWNERS
+++ b/cmds/statsd/OWNERS
@@ -1,9 +1 @@
-jeffreyhuang@google.com
-joeo@google.com
-jtnguyen@google.com
-muhammadq@google.com
-ruchirr@google.com
-singhtejinder@google.com
-tsaichristine@google.com
-yaochen@google.com
-yro@google.com
+baligh@google.com
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
deleted file mode 100644
index ff5717e..0000000
--- a/cmds/statsd/src/atom_field_options.proto
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-option java_package = "com.android.os";
-option java_multiple_files = true;
-option java_outer_classname = "AtomFieldOptions";
-
-import "google/protobuf/descriptor.proto";
-
-// Used to annotate an atom that represents a state change. A state change atom must have exactly
-// ONE exclusive state field, and any number of primary key fields. For example, message
-// UidProcessStateChanged {
-//    optional int32 uid = 1 [(state_field_option).primary_field = true];
-//    optional android.app.ProcessStateEnum state =
-//            2 [(state_field_option).exclusive_state = true];
-//  }
-// Each UidProcessStateChanged atom event represents a state change for a specific uid.
-// A new state automatically overrides the previous state.
-//
-// If the atom has 2 or more primary fields, it means the combination of the
-// primary fields are the primary key.
-// For example:
-// message ThreadStateChanged {
-//    optional int32 pid = 1  [(state_field_option).primary_field = true];
-//    optional int32 tid = 2  [(state_field_option).primary_field = true];
-//    optional int32 state = 3 [(state_field_option).exclusive_state = true];
-// }
-//
-// Sometimes, there is no primary key field, when the state is GLOBAL.
-// For example,
-// message ScreenStateChanged {
-//    optional android.view.DisplayStateEnum state =
-//          1 [(state_field_option).exclusive_state = true];
-// }
-//
-// For state atoms with attribution chain, sometimes the primary key is the first uid in the chain.
-// For example:
-// message AudioStateChanged {
-//   repeated AttributionNode attribution_node = 1
-//       [(stateFieldOption).primary_field_first_uid = true];
-//
-//    enum State {
-//      OFF = 0;
-//      ON = 1;
-//      // RESET indicates all audio stopped. Used when it (re)starts (e.g. after it crashes).
-//      RESET = 2;
-//    }
-//    optional State state = 2 [(stateFieldOption).exclusive_state = true];
-// }
-message StateAtomFieldOption {
-    // Fields that represent the key that the state belongs to.
-    // Used on simple proto fields. Do not use on attribution chains.
-    optional bool primary_field = 1 [default = false];
-
-    // The field that represents the state. It's an exclusive state.
-    optional bool exclusive_state = 2 [default = false];
-
-    // Used on an attribution chain field to indicate that the first uid is the
-    // primary field.
-    optional bool primary_field_first_uid = 3 [default = false];
-
-    // Note: We cannot annotate directly on the enums because many enums are imported from other
-    // proto files in the platform. proto-lite cc library does not support annotations unfortunately
-
-    // Knowing the default state value allows state trackers to remove entries that become the
-    // default state. If there is no default value specified, the default value is unknown, and all
-    // states will be tracked in memory.
-    optional int32 default_state_value = 4;
-
-    // A reset state signals all states go to default value. For example, BLE reset means all active
-    // BLE scans are to be turned off.
-    optional int32 trigger_state_reset_value = 5;
-
-    // If the state change needs to count nesting.
-    optional bool nested = 6 [default = true];
-}
-
-// Used to generate StatsLog.write APIs.
-enum LogMode {
-    MODE_UNSET = 0;
-    // Log fields as their actual types e.g., all primary data types.
-    // Or fields that are hardcoded in stats_log_api_gen tool e.g., AttributionNode
-    MODE_AUTOMATIC = 1;
-    // Log fields in their proto binary format. These fields will not be parsed in statsd
-    MODE_BYTES = 2;
-}
-
-extend google.protobuf.FieldOptions {
-    // Flags to decorate an atom that presents a state change.
-    optional StateAtomFieldOption state_field_option = 50000;
-
-    // Flags to decorate the uid fields in an atom.
-    optional bool is_uid = 50001 [default = false];
-
-    optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
-
-    repeated string module = 50004;
-
-    optional bool truncate_timestamp = 50005 [default = false];
-}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
deleted file mode 100644
index 8363e9f..0000000
--- a/cmds/statsd/src/atoms.proto
+++ /dev/null
@@ -1,12608 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-option java_package = "com.android.os";
-option java_outer_classname = "AtomsProto";
-
-import "frameworks/base/cmds/statsd/src/atom_field_options.proto";
-import "frameworks/base/core/proto/android/app/enums.proto";
-import "frameworks/base/core/proto/android/app/job/enums.proto";
-import "frameworks/base/core/proto/android/app/settings_enums.proto";
-import "frameworks/base/core/proto/android/app/media_output_enum.proto";
-import "frameworks/base/core/proto/android/app/tvsettings_enums.proto";
-import "frameworks/base/core/proto/android/bluetooth/a2dp/enums.proto";
-import "frameworks/base/core/proto/android/bluetooth/enums.proto";
-import "frameworks/base/core/proto/android/bluetooth/hci/enums.proto";
-import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto";
-import "frameworks/base/core/proto/android/bluetooth/smp/enums.proto";
-import "frameworks/base/core/proto/android/debug/enums.proto";
-import "frameworks/base/core/proto/android/hardware/biometrics/enums.proto";
-import "frameworks/base/core/proto/android/hardware/sensor/assist/enums.proto";
-import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
-import "frameworks/base/core/proto/android/os/enums.proto";
-import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
-import "frameworks/base/core/proto/android/server/enums.proto";
-import "frameworks/base/core/proto/android/server/job/enums.proto";
-import "frameworks/base/core/proto/android/server/location/enums.proto";
-import "frameworks/base/core/proto/android/service/procstats_enum.proto";
-import "frameworks/base/core/proto/android/service/usb.proto";
-import "frameworks/base/core/proto/android/stats/camera/camera.proto";
-import "frameworks/base/core/proto/android/stats/connectivity/network_stack.proto";
-import "frameworks/base/core/proto/android/stats/connectivity/tethering.proto";
-import "frameworks/base/core/proto/android/stats/dnsresolver/dns_resolver.proto";
-import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
-import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto";
-import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto";
-import "frameworks/base/core/proto/android/stats/accessibility/accessibility_enums.proto";
-import "frameworks/base/core/proto/android/stats/enums.proto";
-import "frameworks/base/core/proto/android/stats/hdmi/enums.proto";
-import "frameworks/base/core/proto/android/stats/intelligence/enums.proto";
-import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
-import "frameworks/base/core/proto/android/stats/location/location_enums.proto";
-import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto";
-import "frameworks/base/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto";
-import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
-import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
-import "frameworks/base/core/proto/android/stats/sysui/notification_enums.proto";
-import "frameworks/base/core/proto/android/stats/tls/enums.proto";
-import "frameworks/base/core/proto/android/stats/tv/tif_enums.proto";
-import "frameworks/base/core/proto/android/telecomm/enums.proto";
-import "frameworks/base/core/proto/android/telephony/enums.proto";
-import "frameworks/base/core/proto/android/view/enums.proto";
-import "frameworks/base/core/proto/android/wifi/enums.proto";
-import "frameworks/base/core/proto/android/stats/textclassifier/textclassifier_enums.proto";
-import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto";
-
-/**
- * The primary atom class. This message defines all of the available
- * raw stats log events from the Android system, also known as "atoms."
- *
- * This field contains a single oneof with all of the available messages.
- * The stats-log-api-gen tool runs as part of the Android build and
- * generates the android.util.StatsLog class, which contains the constants
- * and methods that Android uses to log.
- *
- * This Atom class is not actually built into the Android system.
- * Instead, statsd on Android constructs these messages synthetically,
- * in the format defined here and in stats_log.proto.
- */
-message Atom {
-    // Pushed atoms start at 2.
-    oneof pushed {
-        // For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
-        BleScanStateChanged ble_scan_state_changed = 2
-                [(module) = "bluetooth", (module) = "statsdtest"];
-        ProcessStateChanged process_state_changed = 3 [(module) = "framework"];
-        BleScanResultReceived ble_scan_result_received = 4 [(module) = "bluetooth"];
-        SensorStateChanged sensor_state_changed =
-                5 [(module) = "framework", (module) = "statsdtest"];
-        GpsScanStateChanged gps_scan_state_changed = 6 [(module) = "framework"];
-        SyncStateChanged sync_state_changed = 7 [(module) = "framework", (module) = "statsdtest"];
-        ScheduledJobStateChanged scheduled_job_state_changed =
-                8 [(module) = "framework", (module) = "statsdtest"];
-        ScreenBrightnessChanged screen_brightness_changed =
-                9 [(module) = "framework", (module) = "statsdtest"];
-        WakelockStateChanged wakelock_state_changed =
-                10 [(module) = "framework", (module) = "statsdtest"];
-        LongPartialWakelockStateChanged long_partial_wakelock_state_changed =
-                11 [(module) = "framework"];
-        MobileRadioPowerStateChanged mobile_radio_power_state_changed =
-                12 [(module) = "framework", (truncate_timestamp) = true];
-        WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13 [(module) = "framework"];
-        ActivityManagerSleepStateChanged activity_manager_sleep_state_changed =
-                14 [(module) = "framework"];
-        MemoryFactorStateChanged memory_factor_state_changed = 15 [(module) = "framework"];
-        ExcessiveCpuUsageReported excessive_cpu_usage_reported = 16 [(module) = "framework"];
-        CachedKillReported cached_kill_reported = 17 [(module) = "framework"];
-        ProcessMemoryStatReported process_memory_stat_reported = 18 [(module) = "framework"];
-        LauncherUIChanged launcher_event = 19 [(module) = "sysui"];
-        BatterySaverModeStateChanged battery_saver_mode_state_changed =
-                20 [(module) = "framework", (module) = "statsdtest"];
-        DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"];
-        DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22 [(module) = "framework"];
-        AudioStateChanged audio_state_changed =
-                23 [(module) = "framework", (truncate_timestamp) = true];
-        MediaCodecStateChanged media_codec_state_changed = 24 [(module) = "framework"];
-        CameraStateChanged camera_state_changed = 25 [(module) = "framework"];
-        FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"];
-        UidProcessStateChanged uid_process_state_changed =
-                27 [(module) = "framework", (module) = "statsdtest"];
-        ProcessLifeCycleStateChanged process_life_cycle_state_changed =
-                28 [(module) = "framework", (module) = "statsdtest"];
-        ScreenStateChanged screen_state_changed =
-                29 [(module) = "framework", (module) = "statsdtest"];
-        BatteryLevelChanged battery_level_changed =
-                30 [(module) = "framework", (module) = "statsdtest"];
-        ChargingStateChanged charging_state_changed = 31 [(module) = "framework"];
-        PluggedStateChanged plugged_state_changed = 32
-                [(module) = "framework", (module) = "statsdtest"];
-        InteractiveStateChanged interactive_state_changed = 33 [(module) = "framework"];
-        TouchEventReported touch_event_reported = 34;
-        WakeupAlarmOccurred wakeup_alarm_occurred = 35 [(module) = "framework"];
-        KernelWakeupReported kernel_wakeup_reported = 36 [(module) = "framework"];
-        WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"];
-        WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"];
-        WifiScanStateChanged wifi_scan_state_changed = 39 [(module) = "wifi"];
-        PhoneSignalStrengthChanged phone_signal_strength_changed =
-                40 [(module) = "framework", (truncate_timestamp) = true];
-        SettingChanged setting_changed = 41 [(module) = "framework"];
-        ActivityForegroundStateChanged activity_foreground_state_changed =
-                42 [(module) = "framework", (module) = "statsdtest"];
-        IsolatedUidChanged isolated_uid_changed =
-                43 [(module) = "framework", (module) = "statsd", (module) = "statsdtest"];
-        PacketWakeupOccurred packet_wakeup_occurred = 44 [(module) = "framework"];
-        WallClockTimeShifted wall_clock_time_shifted = 45 [(module) = "framework"];
-        AnomalyDetected anomaly_detected = 46 [(module) = "statsd"];
-        AppBreadcrumbReported app_breadcrumb_reported = 47 [(module) = "statsd"];
-        AppStartOccurred app_start_occurred = 48 [(module) = "framework", (module) = "statsdtest"];
-        AppStartCanceled app_start_canceled = 49 [(module) = "framework"];
-        AppStartFullyDrawn app_start_fully_drawn = 50 [(module) = "framework"];
-        LmkKillOccurred lmk_kill_occurred = 51 [(module) = "lmkd"];
-        PictureInPictureStateChanged picture_in_picture_state_changed = 52 [(module) = "framework"];
-        WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53 [(module) = "wifi"];
-        LmkStateChanged lmk_state_changed = 54 [(module) = "lmkd"];
-        AppStartMemoryStateCaptured app_start_memory_state_captured = 55 [(module) = "framework"];
-        ShutdownSequenceReported shutdown_sequence_reported = 56 [(module) = "framework"];
-        BootSequenceReported boot_sequence_reported = 57;
-        DaveyOccurred davey_occurred = 58 [(module) = "statsd", deprecated = true];
-        OverlayStateChanged overlay_state_changed =
-                59 [(module) = "framework", (module) = "statsdtest"];
-        ForegroundServiceStateChanged foreground_service_state_changed
-                = 60 [(module) = "framework"];
-        CallStateChanged call_state_changed =
-                61 [(module) = "telecom", (truncate_timestamp) = true];
-        KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"];
-        KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"];
-        KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"];
-        AppDied app_died = 65 [(module) = "framework"];
-        ResourceConfigurationChanged resource_configuration_changed = 66 [(module) = "framework"];
-        BluetoothEnabledStateChanged bluetooth_enabled_state_changed = 67 [(module) = "framework"];
-        BluetoothConnectionStateChanged bluetooth_connection_state_changed =
-                68 [(module) = "bluetooth"];
-        GpsSignalQualityChanged gps_signal_quality_changed = 69 [(module) = "framework"];
-        UsbConnectorStateChanged usb_connector_state_changed = 70 [(module) = "framework"];
-        SpeakerImpedanceReported speaker_impedance_reported = 71;
-        HardwareFailed hardware_failed = 72;
-        PhysicalDropDetected physical_drop_detected = 73;
-        ChargeCyclesReported charge_cycles_reported = 74;
-        MobileConnectionStateChanged mobile_connection_state_changed = 75 [(module) = "telephony"];
-        MobileRadioTechnologyChanged mobile_radio_technology_changed = 76 [(module) = "telephony"];
-        UsbDeviceAttached usb_device_attached = 77 [(module) = "framework"];
-        AppCrashOccurred app_crash_occurred = 78 [(module) = "framework", (module) = "statsdtest"];
-        ANROccurred anr_occurred = 79 [(module) = "framework"];
-        WTFOccurred wtf_occurred = 80 [(module) = "framework"];
-        LowMemReported low_mem_reported = 81 [(module) = "framework"];
-        GenericAtom generic_atom = 82;
-        KeyValuePairsAtom key_value_pairs_atom = 83 [(module) = "framework", (module) = "statsd"];
-        VibratorStateChanged vibrator_state_changed = 84 [(module) = "framework"];
-        DeferredJobStatsReported deferred_job_stats_reported = 85 [(module) = "framework"];
-        ThermalThrottlingStateChanged thermal_throttling = 86 [deprecated=true];
-        BiometricAcquired biometric_acquired = 87 [(module) = "framework"];
-        BiometricAuthenticated biometric_authenticated = 88 [(module) = "framework"];
-        BiometricErrorOccurred biometric_error_occurred = 89 [(module) = "framework"];
-        UiEventReported ui_event_reported = 90 [(module) = "framework", (module) = "sysui"];
-        BatteryHealthSnapshot battery_health_snapshot = 91;
-        SlowIo slow_io = 92;
-        BatteryCausedShutdown battery_caused_shutdown = 93;
-        PhoneServiceStateChanged phone_service_state_changed = 94 [(module) = "framework"];
-        PhoneStateChanged phone_state_changed = 95 [(module) = "framework"];
-        UserRestrictionChanged user_restriction_changed = 96;
-        SettingsUIChanged settings_ui_changed = 97 [(module) = "settings"];
-        ConnectivityStateChanged connectivity_state_changed = 98 [(module) = "framework"];
-        // TODO: service state change is very noisy shortly after boot, as well
-        // as at other transitions - coming out of doze, device plugged in, etc.
-        // Consider removing this if it becomes a problem
-        ServiceStateChanged service_state_changed = 99 [(module) = "framework"];
-        ServiceLaunchReported service_launch_reported = 100 [(module) = "framework"];
-        FlagFlipUpdateOccurred flag_flip_update_occurred = 101 [(module) = "framework"];
-        BinaryPushStateChanged binary_push_state_changed = 102 [(module) = "statsd"];
-        DevicePolicyEvent device_policy_event = 103 [(module) = "framework"];
-        DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104 [(module) = "docsui"];
-        DocsUIFileOperationCopyMoveModeReported docs_ui_file_op_copy_move_mode_reported =
-            105 [(module) = "docsui"];
-        DocsUIFileOperationFailureReported docs_ui_file_op_failure = 106 [(module) = "docsui"];
-        DocsUIFileOperationReported docs_ui_provider_file_op = 107 [(module) = "docsui"];
-        DocsUIInvalidScopedAccessRequestReported docs_ui_invalid_scoped_access_request =
-            108 [(module) = "docsui"];
-        DocsUILaunchReported docs_ui_launch_reported = 109 [(module) = "docsui"];
-        DocsUIRootVisitedReported docs_ui_root_visited = 110 [(module) = "docsui"];
-        DocsUIStartupMsReported docs_ui_startup_ms = 111 [(module) = "docsui"];
-        DocsUIUserActionReported docs_ui_user_action_reported = 112 [(module) = "docsui"];
-        WifiEnabledStateChanged wifi_enabled_state_changed = 113 [(module) = "framework"];
-        WifiRunningStateChanged wifi_running_state_changed = 114
-                [(module) = "framework", deprecated = true];
-        AppCompacted app_compacted = 115 [(module) = "framework"];
-        NetworkDnsEventReported network_dns_event_reported = 116 [(module) = "resolv"];
-        DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported =
-            117 [(module) = "docsui"];
-        DocsUIPickResultReported docs_ui_pick_result_reported = 118 [(module) = "docsui"];
-        DocsUISearchModeReported docs_ui_search_mode_reported = 119 [(module) = "docsui"];
-        DocsUISearchTypeReported docs_ui_search_type_reported = 120 [(module) = "docsui"];
-        DataStallEvent data_stall_event = 121 [(module) = "network_stack"];
-        RescuePartyResetReported rescue_party_reset_reported = 122 [(module) = "framework"];
-        SignedConfigReported signed_config_reported = 123 [(module) = "framework"];
-        GnssNiEventReported gnss_ni_event_reported = 124 [(module) = "framework"];
-        BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event =
-                125 [(module) = "bluetooth"];
-        BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed =
-                126 [(module) = "bluetooth"];
-        BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed =
-                127 [(module) = "bluetooth"];
-        AppDowngraded app_downgraded = 128 [(module) = "framework"];
-        AppOptimizedAfterDowngraded app_optimized_after_downgraded = 129;
-        LowStorageStateChanged low_storage_state_changed = 130 [(module) = "framework"];
-        GnssNfwNotificationReported gnss_nfw_notification_reported = 131 [(module) = "framework"];
-        GnssConfigurationReported gnss_configuration_reported = 132 [(module) = "framework"];
-        UsbPortOverheatEvent usb_port_overheat_event_reported = 133;
-        NfcErrorOccurred nfc_error_occurred = 134 [(module) = "nfc"];
-        NfcStateChanged nfc_state_changed = 135 [(module) = "nfc"];
-        NfcBeamOccurred nfc_beam_occurred = 136 [(module) = "nfc"];
-        NfcCardemulationOccurred nfc_cardemulation_occurred = 137 [(module) = "nfc"];
-        NfcTagOccurred nfc_tag_occurred = 138 [(module) = "nfc"];
-        NfcHceTransactionOccurred nfc_hce_transaction_occurred = 139 [(module) = "nfc"];
-        SeStateChanged se_state_changed = 140 [(module) = "secure_element"];
-        SeOmapiReported se_omapi_reported = 141 [(module) = "secure_element"];
-        BroadcastDispatchLatencyReported broadcast_dispatch_latency_reported =
-                142 [(module) = "framework"];
-        AttentionManagerServiceResultReported attention_manager_service_result_reported =
-                143 [(module) = "framework"];
-        AdbConnectionChanged adb_connection_changed = 144 [(module) = "framework"];
-        SpeechDspStatReported speech_dsp_stat_reported = 145;
-        UsbContaminantReported usb_contaminant_reported = 146 [(module) = "framework"];
-        WatchdogRollbackOccurred watchdog_rollback_occurred =
-                147 [(module) = "framework", (module) = "statsd"];
-        BiometricSystemHealthIssueDetected biometric_system_health_issue_detected =
-                148 [(module) = "framework"];
-        BubbleUIChanged bubble_ui_changed = 149 [(module) = "framework"];
-        ScheduledJobConstraintChanged scheduled_job_constraint_changed =
-                150 [(module) = "framework"];
-        BluetoothActiveDeviceChanged bluetooth_active_device_changed =
-                151 [(module) = "bluetooth"];
-        BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed =
-                152 [(module) = "bluetooth"];
-        BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed =
-                153 [(module) = "bluetooth"];
-        BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed =
-                154 [(module) = "bluetooth"];
-        BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported =
-                155 [(module) = "bluetooth"];
-        BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported =
-                156 [(module) = "bluetooth"];
-        BluetoothDeviceRssiReported bluetooth_device_rssi_reported =
-                157 [(module) = "bluetooth"];
-        BluetoothDeviceFailedContactCounterReported
-                bluetooth_device_failed_contact_counter_reported = 158 [(module) = "bluetooth"];
-        BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported =
-                159 [(module) = "bluetooth"];
-        BluetoothHciTimeoutReported bluetooth_hci_timeout_reported =
-                160 [(module) = "bluetooth"];
-        BluetoothQualityReportReported bluetooth_quality_report_reported =
-                161 [(module) = "bluetooth"];
-        BluetoothDeviceInfoReported bluetooth_device_info_reported =
-                162 [(module) = "bluetooth"];
-        BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported =
-                163 [(module) = "bluetooth"];
-        BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported =
-                164 [(module) = "bluetooth"];
-        BluetoothBondStateChanged bluetooth_bond_state_changed =
-                165 [(module) = "bluetooth"];
-        BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported =
-                166 [(module) = "bluetooth"];
-        BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported =
-                167 [(module) = "bluetooth"];
-        ScreenTimeoutExtensionReported screen_timeout_extension_reported =
-                168 [(module) = "framework"];
-        ProcessStartTime process_start_time = 169 [(module) = "framework"];
-        PermissionGrantRequestResultReported permission_grant_request_result_reported =
-                170 [(module) = "permissioncontroller"];
-        BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
-        DeviceIdentifierAccessDenied device_identifier_access_denied =
-                172 [(module) = "telephony_common"];
-        BubbleDeveloperErrorReported bubble_developer_error_reported = 173 [(module) = "framework"];
-        AssistGestureStageReported assist_gesture_stage_reported = 174 [(module) = "sysui"];
-        AssistGestureFeedbackReported assist_gesture_feedback_reported = 175 [(module) = "sysui"];
-        AssistGestureProgressReported assist_gesture_progress_reported = 176 [(module) = "sysui"];
-        TouchGestureClassified touch_gesture_classified = 177 [(module) = "framework"];
-        HiddenApiUsed hidden_api_used = 178 [(module) = "framework"];
-        StyleUIChanged style_ui_changed = 179 [(module) = "sysui"];
-        PrivacyIndicatorsInteracted privacy_indicators_interacted =
-                180 [(module) = "permissioncontroller"];
-        AppInstallOnExternalStorageReported app_install_on_external_storage_reported =
-                181 [(module) = "framework"];
-        NetworkStackReported network_stack_reported = 182 [(module) = "network_stack"];
-        AppMovedStorageReported app_moved_storage_reported = 183 [(module) = "framework"];
-        BiometricEnrolled biometric_enrolled = 184 [(module) = "framework"];
-        SystemServerWatchdogOccurred system_server_watchdog_occurred = 185 [(module) = "framework"];
-        TombStoneOccurred tomb_stone_occurred = 186 [(module) = "framework"];
-        BluetoothClassOfDeviceReported bluetooth_class_of_device_reported =
-                187 [(module) = "bluetooth"];
-        IntelligenceEventReported intelligence_event_reported =
-                188 [(module) = "intelligence"];
-        ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed =
-                189 [(module) = "framework"];
-        RoleRequestResultReported role_request_result_reported =
-                190 [(module) = "permissioncontroller"];
-        MediametricsAudiopolicyReported mediametrics_audiopolicy_reported = 191;
-        MediametricsAudiorecordReported mediametrics_audiorecord_reported = 192;
-        MediametricsAudiothreadReported mediametrics_audiothread_reported = 193;
-        MediametricsAudiotrackReported mediametrics_audiotrack_reported = 194;
-        MediametricsCodecReported mediametrics_codec_reported = 195;
-        MediametricsDrmWidevineReported mediametrics_drm_widevine_reported = 196;
-        MediametricsExtractorReported mediametrics_extractor_reported = 197;
-        MediametricsMediadrmReported mediametrics_mediadrm_reported = 198;
-        MediametricsNuPlayerReported mediametrics_nuplayer_reported = 199;
-        MediametricsRecorderReported mediametrics_recorder_reported = 200;
-        MediametricsDrmManagerReported mediametrics_drmmanager_reported = 201;
-        CarPowerStateChanged car_power_state_changed = 203 [(module) = "car"];
-        GarageModeInfo garage_mode_info = 204 [(module) = "car"];
-        TestAtomReported test_atom_reported = 205 [(module) = "cts"];
-        ContentCaptureCallerMismatchReported content_capture_caller_mismatch_reported =
-                206 [(module) = "framework"];
-        ContentCaptureServiceEvents content_capture_service_events = 207 [(module) = "framework"];
-        ContentCaptureSessionEvents content_capture_session_events = 208 [(module) = "framework"];
-        ContentCaptureFlushed content_capture_flushed = 209 [(module) = "framework"];
-        LocationManagerApiUsageReported location_manager_api_usage_reported =
-                210 [(module) = "framework"];
-        ReviewPermissionsFragmentResultReported review_permissions_fragment_result_reported =
-                211 [(module) = "permissioncontroller"];
-        RuntimePermissionsUpgradeResult runtime_permissions_upgrade_result =
-                212 [(module) = "permissioncontroller"];
-        GrantPermissionsActivityButtonActions grant_permissions_activity_button_actions =
-                213 [(module) = "permissioncontroller"];
-        LocationAccessCheckNotificationAction location_access_check_notification_action =
-                214 [(module) = "permissioncontroller"];
-        AppPermissionFragmentActionReported app_permission_fragment_action_reported =
-                215 [(module) = "permissioncontroller"];
-        AppPermissionFragmentViewed app_permission_fragment_viewed =
-                216 [(module) = "permissioncontroller"];
-        AppPermissionsFragmentViewed app_permissions_fragment_viewed =
-                217 [(module) = "permissioncontroller"];
-        PermissionAppsFragmentViewed permission_apps_fragment_viewed =
-                218  [(module) = "permissioncontroller"];
-        TextSelectionEvent text_selection_event = 219  [(module) = "textclassifier"];
-        TextLinkifyEvent text_linkify_event = 220  [(module) = "textclassifier"];
-        ConversationActionsEvent conversation_actions_event = 221  [(module) = "textclassifier"];
-        LanguageDetectionEvent language_detection_event = 222  [(module) = "textclassifier"];
-        ExclusionRectStateChanged exclusion_rect_state_changed = 223 [(module) = "framework"];
-        BackGesture back_gesture_reported_reported = 224 [(module) = "sysui"];
-        UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225;
-        UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226;
-        CameraActionEvent camera_action_event = 227 [(module) = "framework"];
-        AppCompatibilityChangeReported app_compatibility_change_reported =
-                228 [(module) = "framework"];
-        PerfettoUploaded perfetto_uploaded = 229 [(module) = "perfetto"];
-        VmsClientConnectionStateChanged vms_client_connection_state_changed =
-                230 [(module) = "car"];
-        MediaProviderScanOccurred media_provider_scan_occurred = 233 [(module) = "mediaprovider"];
-        MediaContentDeleted media_content_deleted = 234 [(module) = "mediaprovider"];
-        MediaProviderPermissionRequested media_provider_permission_requested =
-            235 [(module) = "mediaprovider"];
-        MediaProviderSchemaChanged media_provider_schema_changed = 236 [(module) = "mediaprovider"];
-        MediaProviderIdleMaintenanceFinished media_provider_idle_maintenance_finished =
-            237 [(module) = "mediaprovider"];
-        RebootEscrowRecoveryReported reboot_escrow_recovery_reported = 238 [(module) = "framework"];
-        BootTimeEventDuration boot_time_event_duration_reported = 239 [(module) = "framework"];
-        BootTimeEventElapsedTime boot_time_event_elapsed_time_reported =
-                240 [(module) = "framework"];
-        BootTimeEventUtcTime boot_time_event_utc_time_reported = 241;
-        BootTimeEventErrorCode boot_time_event_error_code_reported = 242 [(module) = "framework"];
-        UserspaceRebootReported userspace_reboot_reported = 243 [(module) = "framework"];
-        NotificationReported notification_reported = 244 [(module) = "framework"];
-        NotificationPanelReported notification_panel_reported = 245 [(module) = "sysui"];
-        NotificationChannelModified notification_channel_modified = 246 [(module) = "framework"];
-        IntegrityCheckResultReported integrity_check_result_reported = 247 [(module) = "framework"];
-        IntegrityRulesPushed integrity_rules_pushed = 248 [(module) = "framework"];
-        CellBroadcastMessageReported cb_message_reported =
-            249 [(module) = "cellbroadcast"];
-        CellBroadcastMessageError cb_message_error =
-            250 [(module) = "cellbroadcast"];
-        WifiHealthStatReported wifi_health_stat_reported = 251 [(module) = "wifi"];
-        WifiFailureStatReported wifi_failure_stat_reported = 252 [(module) = "wifi"];
-        WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"];
-        AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"];
-        SnapshotMergeReported snapshot_merge_reported = 255;
-        ForegroundServiceAppOpSessionEnded foreground_service_app_op_session_ended =
-            256  [(module) = "framework"];
-        DisplayJankReported display_jank_reported = 257;
-        AppStandbyBucketChanged app_standby_bucket_changed = 258 [(module) = "framework"];
-        SharesheetStarted sharesheet_started = 259 [(module) = "framework"];
-        RankingSelected ranking_selected = 260 [(module) = "framework", (module) = "sysui"];
-        TvSettingsUIInteracted tvsettings_ui_interacted = 261 [(module) = "tv_settings"];
-        LauncherStaticLayout launcher_snapshot = 262 [(module) = "sysui"];
-        PackageInstallerV2Reported package_installer_v2_reported = 263 [(module) = "framework"];
-        UserLifecycleJourneyReported user_lifecycle_journey_reported = 264 [(module) = "framework"];
-        UserLifecycleEventOccurred user_lifecycle_event_occurred = 265 [(module) = "framework"];
-        AccessibilityShortcutReported accessibility_shortcut_reported =
-            266 [(module) = "framework"];
-        AccessibilityServiceReported accessibility_service_reported = 267 [(module) = "settings"];
-        DocsUIDragAndDropReported docs_ui_drag_and_drop_reported = 268 [(module) = "docsui"];
-        AppUsageEventOccurred app_usage_event_occurred = 269 [(module) = "framework"];
-        AutoRevokeNotificationClicked auto_revoke_notification_clicked =
-            270 [(module) = "permissioncontroller"];
-        AutoRevokeFragmentAppViewed auto_revoke_fragment_app_viewed =
-            271 [(module) = "permissioncontroller"];
-        AutoRevokedAppInteraction auto_revoked_app_interaction =
-            272 [(module) = "permissioncontroller", (module) = "settings"];
-        AppPermissionGroupsFragmentAutoRevokeAction
-            app_permission_groups_fragment_auto_revoke_action =
-            273 [(module) = "permissioncontroller"];
-        EvsUsageStatsReported evs_usage_stats_reported = 274 [(module) = "evs"];
-        AudioPowerUsageDataReported audio_power_usage_data_reported = 275;
-        TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"];
-        MediaOutputOpSwitchReported mediaoutput_op_switch_reported =
-            277 [(module) = "settings"];
-        CellBroadcastMessageFiltered cb_message_filtered =
-            278 [(module) = "cellbroadcast"];
-        TvTunerDvrStatus tv_tuner_dvr_status = 279 [(module) = "framework"];
-        TvCasSessionOpenStatus tv_cas_session_open_status =
-            280 [(module) = "framework"];
-        AssistantInvocationReported assistant_invocation_reported = 281 [(module) = "framework"];
-        DisplayWakeReported display_wake_reported = 282 [(module) = "framework"];
-        CarUserHalModifyUserRequestReported car_user_hal_modify_user_request_reported =
-            283 [(module) = "car"];
-        CarUserHalModifyUserResponseReported car_user_hal_modify_user_response_reported =
-            284 [(module) = "car"];
-        CarUserHalPostSwitchResponseReported car_user_hal_post_switch_response_reported =
-            285 [(module) = "car"];
-        CarUserHalInitialUserInfoRequestReported car_user_hal_initial_user_info_request_reported =
-            286 [(module) = "car"];
-        CarUserHalInitialUserInfoResponseReported car_user_hal_initial_user_info_response_reported =
-            287 [(module) = "car"];
-        CarUserHalUserAssociationRequestReported car_user_hal_user_association_request_reported =
-            288 [(module) = "car"];
-        CarUserHalSetUserAssociationResponseReported car_user_hal_set_user_association_response_reported =
-            289 [(module) = "car"];
-        NetworkIpProvisioningReported network_ip_provisioning_reported =
-            290 [(module) = "network_stack"];
-        NetworkDhcpRenewReported network_dhcp_renew_reported = 291 [(module) = "network_stack"];
-        NetworkValidationReported network_validation_reported = 292 [(module) = "network_stack"];
-        NetworkStackQuirkReported network_stack_quirk_reported = 293 [(module) = "network_stack"];
-        MediametricsAudioRecordDeviceUsageReported mediametrics_audiorecorddeviceusage_reported =
-            294;
-        MediametricsAudioThreadDeviceUsageReported mediametrics_audiothreaddeviceusage_reported =
-            295;
-        MediametricsAudioTrackDeviceUsageReported mediametrics_audiotrackdeviceusage_reported =
-            296;
-        MediametricsAudioDeviceConnectionReported mediametrics_audiodeviceconnection_reported =
-            297;
-        BlobCommitted blob_committed = 298 [(module) = "framework"];
-        BlobLeased blob_leased = 299 [(module) = "framework"];
-        BlobOpened blob_opened = 300 [(module) = "framework"];
-        ContactsProviderStatusReported contacts_provider_status_reported = 301;
-        KeystoreKeyEventReported keystore_key_event_reported = 302;
-        NetworkTetheringReported  network_tethering_reported =
-            303 [(module) = "network_tethering"];
-        ImeTouchReported ime_touch_reported = 304 [(module) = "sysui"];
-        UIInteractionFrameInfoReported ui_interaction_frame_info_reported =
-            305 [(module) = "framework"];
-        UIActionLatencyReported ui_action_latency_reported = 306 [(module) = "framework"];
-        WifiDisconnectReported wifi_disconnect_reported = 307 [(module) = "wifi"];
-        WifiConnectionStateChanged wifi_connection_state_changed = 308 [(module) = "wifi"];
-        HdmiCecActiveSourceChanged hdmi_cec_active_source_changed = 309 [(module) = "framework"];
-        HdmiCecMessageReported hdmi_cec_message_reported = 310 [(module) = "framework"];
-        AirplaneMode airplane_mode = 311 [(module) = "telephony"];
-        ModemRestart modem_restart = 312 [(module) = "telephony"];
-        CarrierIdMismatchReported carrier_id_mismatch_reported = 313 [(module) = "telephony"];
-        CarrierIdTableUpdated carrier_id_table_updated = 314 [(module) = "telephony"];
-        DataStallRecoveryReported data_stall_recovery_reported = 315 [(module) = "telephony"];
-        MediametricsMediaParserReported mediametrics_mediaparser_reported = 316;
-        TlsHandshakeReported tls_handshake_reported = 317 [(module) = "conscrypt"];
-        TextClassifierApiUsageReported text_classifier_api_usage_reported = 318  [(module) = "textclassifier"];
-        KilledAppStatsReported killed_app_stats_reported = 319 [(module) = "carwatchdogd"];
-        MediametricsPlaybackReported mediametrics_playback_reported = 320;
-        MediaNetworkInfoChanged media_network_info_changed = 321;
-        MediaPlaybackStateChanged media_playback_state_changed = 322;
-        MediaPlaybackErrorReported media_playback_error_reported = 323;
-        MediaPlaybackTrackChanged media_playback_track_changed = 324;
-        WifiScanReported wifi_scan_reported = 325 [(module) = "wifi"];
-        WifiPnoScanReported wifi_pno_scan_reported = 326  [(module) = "wifi"];
-        TifTuneStateChanged tif_tune_changed = 327 [(module) = "framework"];
-        AutoRotateReported auto_rotate_reported = 328 [(module) = "framework"];
-
-        // StatsdStats tracks platform atoms with ids upto 500.
-        // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
-    }
-
-    // Pulled events will start at field 10000.
-    // Next: 10092
-    oneof pulled {
-        WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
-        WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
-        MobileBytesTransfer mobile_bytes_transfer =
-                10002 [(module) = "framework", (truncate_timestamp) = true];
-        MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg =
-                10003 [(module) = "framework", (truncate_timestamp) = true];
-        BluetoothBytesTransfer bluetooth_bytes_transfer = 10006 [(module) = "framework"];
-        KernelWakelock kernel_wakelock = 10004 [(module) = "framework"];
-        SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"];
-        CpuTimePerFreq cpu_time_per_freq = 10008 [(module) = "framework"];
-        CpuTimePerUid cpu_time_per_uid = 10009 [(module) = "framework", (module) = "statsdtest"];
-        CpuTimePerUidFreq cpu_time_per_uid_freq =
-                10010 [(module) = "framework", (module) = "statsd"];
-        WifiActivityInfo wifi_activity_info = 10011 [(module) = "framework"];
-        ModemActivityInfo modem_activity_info = 10012 [(module) = "framework"];
-        BluetoothActivityInfo bluetooth_activity_info = 10007 [(module) = "framework"];
-        ProcessMemoryState process_memory_state = 10013 [(module) = "framework"];
-        SystemElapsedRealtime system_elapsed_realtime = 10014 [(module) = "framework"];
-        SystemUptime system_uptime = 10015 [(module) = "framework"];
-        CpuActiveTime cpu_active_time = 10016 [(module) = "framework", (module) = "statsdtest"];
-        CpuClusterTime cpu_cluster_time = 10017 [(module) = "framework"];
-        DiskSpace disk_space = 10018 [deprecated=true, (module) = "statsdtest"];
-        RemainingBatteryCapacity remaining_battery_capacity = 10019 [(module) = "framework"];
-        FullBatteryCapacity full_battery_capacity = 10020 [(module) = "framework"];
-        Temperature temperature = 10021 [(module) = "framework", (module) = "statsdtest"];
-        BinderCalls binder_calls = 10022 [(module) = "framework", (module) = "statsd"];
-        BinderCallsExceptions binder_calls_exceptions = 10023 [(module) = "framework"];
-        LooperStats looper_stats = 10024 [(module) = "framework", (module) = "statsd"];
-        DiskStats disk_stats = 10025 [(module) = "framework"];
-        DirectoryUsage directory_usage = 10026 [(module) = "framework"];
-        AppSize app_size = 10027 [(module) = "framework"];
-        CategorySize category_size = 10028 [(module) = "framework"];
-        ProcStats proc_stats = 10029 [(module) = "framework"];
-        BatteryVoltage battery_voltage = 10030 [(module) = "framework"];
-        NumFingerprintsEnrolled num_fingerprints_enrolled = 10031 [(module) = "framework"];
-        DiskIo disk_io = 10032 [(module) = "framework"];
-        PowerProfile power_profile = 10033 [(module) = "framework"];
-        ProcStatsPkgProc proc_stats_pkg_proc = 10034 [(module) = "framework"];
-        ProcessCpuTime process_cpu_time = 10035 [(module) = "framework"];
-        CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037 [(module) = "framework"];
-        OnDevicePowerMeasurement on_device_power_measurement = 10038;
-        DeviceCalculatedPowerUse device_calculated_power_use = 10039 [(module) = "framework"];
-        DeviceCalculatedPowerBlameUid device_calculated_power_blame_uid =
-                10040 [(module) = "framework"];
-        DeviceCalculatedPowerBlameOther device_calculated_power_blame_other =
-                10041 [(module) = "framework"];
-        ProcessMemoryHighWaterMark process_memory_high_water_mark = 10042 [(module) = "framework"];
-        BatteryLevel battery_level = 10043 [(module) = "framework"];
-        BuildInformation build_information = 10044 [(module) = "framework"];
-        BatteryCycleCount battery_cycle_count = 10045 [(module) = "framework"];
-        DebugElapsedClock debug_elapsed_clock = 10046 [(module) = "framework"];
-        DebugFailingElapsedClock debug_failing_elapsed_clock = 10047 [(module) = "framework"];
-        NumFacesEnrolled num_faces_enrolled = 10048 [(module) = "framework"];
-        RoleHolder role_holder = 10049 [(module) = "framework"];
-        DangerousPermissionState dangerous_permission_state = 10050 [(module) = "framework"];
-        TrainInfo train_info = 10051 [(module) = "statsd"];
-        TimeZoneDataInfo time_zone_data_info = 10052 [(module) = "framework"];
-        ExternalStorageInfo external_storage_info = 10053 [(module) = "framework"];
-        GpuStatsGlobalInfo gpu_stats_global_info = 10054;
-        GpuStatsAppInfo gpu_stats_app_info = 10055;
-        SystemIonHeapSize system_ion_heap_size = 10056 [deprecated = true, (module) = "framework"];
-        AppsOnExternalStorageInfo apps_on_external_storage_info = 10057 [(module) = "framework"];
-        FaceSettings face_settings = 10058 [(module) = "framework"];
-        CoolingDevice cooling_device = 10059 [(module) = "framework"];
-        AppOps app_ops = 10060 [(module) = "framework"];
-        ProcessSystemIonHeapSize process_system_ion_heap_size = 10061 [(module) = "framework"];
-        SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062;
-        SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
-        ProcessMemorySnapshot process_memory_snapshot = 10064 [(module) = "framework"];
-        VmsClientStats vms_client_stats = 10065 [(module) = "car"];
-        NotificationRemoteViews notification_remote_views = 10066 [(module) = "framework"];
-        DangerousPermissionStateSampled dangerous_permission_state_sampled =
-                10067 [(module) = "framework"];
-        GraphicsStats graphics_stats = 10068;
-        RuntimeAppOpAccess runtime_app_op_access = 10069 [(module) = "framework"];
-        IonHeapSize ion_heap_size = 10070 [(module) = "framework"];
-        PackageNotificationPreferences package_notification_preferences =
-                10071 [(module) = "framework"];
-        PackageNotificationChannelPreferences package_notification_channel_preferences =
-                10072 [(module) = "framework"];
-        PackageNotificationChannelGroupPreferences package_notification_channel_group_preferences =
-                10073 [(module) = "framework"];
-        GnssStats gnss_stats = 10074 [(module) = "framework"];
-        AttributedAppOps attributed_app_ops = 10075 [(module) = "framework"];
-        VoiceCallSession voice_call_session = 10076 [(module) = "telephony"];
-        VoiceCallRatUsage voice_call_rat_usage = 10077 [(module) = "telephony"];
-        SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
-        SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
-        SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
-        BlobInfo blob_info = 10081 [(module) = "framework"];
-        DataUsageBytesTransfer data_usage_bytes_transfer =
-                10082 [(module) = "framework", (truncate_timestamp) = true];
-        BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered =
-                10083 [(module) = "framework", (truncate_timestamp) = true];
-        DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"];
-        GeneralExternalStorageAccessStats general_external_storage_access_stats =
-            10085 [(module) = "mediaprovider"];
-        IncomingSms incoming_sms = 10086 [(module) = "telephony"];
-        OutgoingSms outgoing_sms = 10087 [(module) = "telephony"];
-        CarrierIdTableVersion carrier_id_table_version = 10088 [(module) = "telephony"];
-        DataCallSession data_call_session = 10089 [(module) = "telephony"];
-        CellularServiceState cellular_service_state = 10090 [(module) = "telephony"];
-        CellularDataServiceSwitch cellular_data_service_switch = 10091 [(module) = "telephony"];
-    }
-
-    // DO NOT USE field numbers above 100,000 in AOSP.
-    // Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
-    // Field numbers 200,000 and above are reserved for future use; do not use them at all.
-
-    reserved 10036;
-}
-
-/**
- * This proto represents a node of an attribution chain.
- * Note: All attribution chains are represented as a repeated field of type
- * AttributionNode. It is understood that in such arrays, the order is that
- * of calls, that is [A, B, C] if A calls B that calls C.
- */
-message AttributionNode {
-    // The uid for a given element in the attribution chain.
-    optional int32 uid = 1;
-
-    // The (optional) string tag for an element in the attribution chain. If the
-    // element has no tag, it is encoded as an empty string.
-    optional string tag = 2;
-}
-
-message KeyValuePair {
-    optional int32 key = 1;
-    oneof value {
-        int32 value_int = 2;
-        int64 value_long = 3;
-        string value_str = 4;
-        float value_float = 5;
-    }
-}
-
-message KeyValuePairsAtom {
-    optional int32 uid = 1;
-    repeated KeyValuePair pairs = 2;
-}
-
-/*
- * *****************************************************************************
- * Below are all of the individual atoms that are logged by Android via statsd.
- *
- * RULES:
- *   - The field ids for each atom must start at 1, and count upwards by 1.
- *     Skipping field ids is not allowed.
- *   - These form an API, so renaming, renumbering or removing fields is
- *     not allowed between android releases.  (This is not currently enforced,
- *     but there will be a tool to enforce this restriction).
- *   - The types must be built-in protocol buffer types, namely, no sub-messages
- *     are allowed (yet).  The bytes type is also not allowed.
- *   - The CamelCase name of the message type should match the
- *     underscore_separated name as defined in Atom.
- *   - If an atom represents work that can be attributed to an app, there can
- *     be exactly one AttributionChain field. It must be field number 1.
- *   - A field that is a uid should be a string field, tagged with the [xxx]
- *     annotation. The generated code on android will be represented by UIDs,
- *     and those UIDs will be translated in xxx to those strings.
- *
- * CONVENTIONS:
- *   - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange.
- *   - If there is a UID, it goes first. Think in an object-oriented fashion.
- * *****************************************************************************
- */
-
-/**
- * This atom is deprecated starting in Q. Please use ThermalThrottlingSeverityStateChanged.
- * Logs when the Thermal service HAL notifies the throttling start/stop events.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java
- */
-message ThermalThrottlingStateChanged {
-    // The type of temperature being reported (CPU, GPU, SKIN, etc)
-    optional android.os.TemperatureTypeEnum sensor_type = 1;
-
-    // Throttling state, this field is DEPRECATED
-    enum State {
-        UNKNOWN = 0;
-        START = 1; // START indicated that throttling was triggered.
-        STOP = 2; // STOP indicates that throttling was cleared.
-    }
-    optional State state = 2;
-
-    optional float temperature = 3;
-}
-
-/**
- * Logs when the screen state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ScreenStateChanged {
-    // New screen state, from frameworks/base/core/proto/android/view/enums.proto.
-    optional android.view.DisplayStateEnum state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs that the process state of the uid, as determined by ActivityManager
- * (i.e. the highest process state of that uid's processes) has changed.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message UidProcessStateChanged {
-    optional int32 uid = 1 [(state_field_option).primary_field = true, (is_uid) = true];
-
-    // The state, from frameworks/base/core/proto/android/app/enums.proto.
-    optional android.app.ProcessStateEnum state = 2
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs process state change of a process, as per the activity manager.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
- */
-message ProcessStateChanged {
-    optional int32 uid = 1;
-    optional string process_name = 2;
-    optional string package_name = 3;
-    // TODO: remove this when validation is done
-    optional int64 version = 5;
-    // The state, from frameworks/base/core/proto/android/app/enums.proto.
-    optional android.app.ProcessStateEnum state = 4;
-}
-
-/**
- * Logs when ActivityManagerService sleep state is changed.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityTaskManagerService.java
- */
-message ActivityManagerSleepStateChanged {
-    // TODO: import frameworks proto
-    enum State {
-        UNKNOWN = 0;
-        ASLEEP = 1;
-        AWAKE = 2;
-    }
-    optional State state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs when system memory state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message MemoryFactorStateChanged {
-    // TODO: import frameworks proto
-    enum State {
-        MEMORY_UNKNOWN = 0;
-        NORMAL = 1;     // normal.
-        MODERATE = 2;   // moderate memory pressure.
-        LOW = 3;        // low memory.
-        CRITICAL = 4;   // critical memory.
-
-    }
-    optional State factor = 1 [(state_field_option).exclusive_state = true];
-}
-
-/**
- * Logs when app is using too much cpu, according to ActivityManagerService.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message ExcessiveCpuUsageReported {
-    optional int32 uid = 1;
-    optional string process_name = 2;
-    optional string package_name = 3;
-    // package version. TODO: remove this when validation is done
-    optional int64 version = 4;
-}
-
-/**
- * Logs when a cached process is killed, along with its pss.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message CachedKillReported {
-    optional int32 uid = 1;
-    optional string process_name = 2;
-    optional string package_name = 3;
-    // TODO: remove this when validation is done
-    optional int64 version = 5;
-    optional int64 pss = 4;
-}
-
-/**
- * Logs the change in wifi health.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiDataStall.java
- */
-message WifiHealthStatReported {
-    enum Band {
-        UNKNOWN = 0;
-        // All of 2.4GHz band
-        BAND_2G = 1;
-        // Frequencies in the range of [5150, 5250) GHz
-        BAND_5G_LOW = 2;
-        // Frequencies in the range of [5250, 5725) GHz
-        BAND_5G_MIDDLE = 3;
-        // Frequencies in the range of [5725, 5850) GHz
-        BAND_5G_HIGH = 4;
-        // Frequencies in the range of [5925, 6425) GHz
-        BAND_6G_LOW = 5;
-        // Frequencies in the range of [6425, 6875) GHz
-        BAND_6G_MIDDLE = 6;
-        // Frequencies in the range of [6875, 7125) GHz
-        BAND_6G_HIGH = 7;
-    }
-    // duration this stat is obtained over in milliseconds
-    optional int32 duration_millis = 1;
-    // whether wifi is classified as sufficient for the user's data traffic, determined
-    // by whether the calculated throughput exceeds the average demand within |duration_millis|
-    optional bool is_sufficient = 2;
-    // whether cellular data is available
-    optional bool is_cell_data_available = 3;
-    // the Band bucket the connected network is on
-    optional Band band = 4;
-}
-
-/**
- * Logged when wifi detects a significant change in connection failure rate.
- *
- * Logged from: frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiHealthMonitor.java
- *
- */
-message WifiFailureStatReported {
-    enum AbnormalityType {
-        UNKNOWN = 0;
-        SIGNIFICANT_INCREASE = 1;
-        SIGNIFICANT_DECREASE = 2;
-        SIMPLY_HIGH = 3;
-    }
-    enum FailureType {
-        FAILURE_UNKNOWN = 0;
-        FAILURE_CONNECTION = 1;
-        FAILURE_ASSOCIATION_REJECTION = 2;
-        FAILURE_ASSOCIATION_TIMEOUT = 3;
-        FAILURE_AUTHENTICATION = 4;
-        FAILURE_NON_LOCAL_DISCONNECTION = 5;
-        FAILURE_SHORT_CONNECTION_DUE_TO_NON_LOCAL_DISCONNECTION = 6;
-    }
-    // Reason for uploading this stat
-    optional AbnormalityType abnormality_type = 1;
-    // The particular type of failure
-    optional FailureType failure_type = 2;
-    // How many times we have encountered this combination of AbnormalityType and FailureType
-    optional int32 failure_count = 3;
-}
-
-/**
- * Logs whether a Wifi connection attempt was successful and reasons for failure if it wasn't.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
- */
-message WifiConnectionResultReported {
-    enum FailureCode {
-        FAILURE_UNKNOWN = 0;
-        FAILURE_ASSOCIATION_TIMEOUT = 1;
-        FAILURE_ASSOCIATION_REJECTION = 2;
-        FAILURE_AUTHENTICATION_GENERAL = 3;
-        FAILURE_AUTHENTICATION_EAP = 4;
-        FAILURE_DHCP = 5;
-        FAILURE_NETWORK_DISCONNECTION = 6;
-        FAILURE_ROAM_TIMEOUT = 7;
-        FAILURE_WRONG_PASSWORD = 8;
-    }
-
-    enum Trigger {
-        UNKNOWN = 0;
-        // Connection attempt was initiated manually.
-        MANUAL = 1;
-        // Automatic reconnection to the same network as connected previously.
-        RECONNECT_SAME_NETWORK = 2;
-        // Automatic reconnection to a saved network, but not the previous one.
-        AUTOCONNECT_CONFIGURED_NETWORK = 3;
-        // Automatic first connection attempt after device boot.
-        AUTOCONNECT_BOOT = 4;
-    }
-
-    // True represents a successful connection.
-    optional bool connection_result = 1;
-    // Reason for the connection failure.
-    optional FailureCode failure_code = 2;
-    // Scan RSSI before the connection attempt.
-    optional int32 rssi = 3;
-    // Time taken by this connection attempt.
-    optional int32 connection_attempt_duration_millis = 4;
-    // Band bucket the connected network is on.
-    optional android.net.wifi.WifiBandBucket band = 5;
-    // Authentication type.
-    optional android.net.wifi.WifiAuthType auth_type = 6;
-    // What triggered this connection attempt.
-    optional Trigger trigger = 7;
-    // Whether this network was used (successfully connected to) previously.
-    optional bool network_used = 8;
-    // Time taken from the last successful connection (or device boot if that's the first one).
-    optional int32 time_since_last_connection_seconds = 9;
-}
-
-/**
- * Logs when a Wifi connection drops.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
- */
-message WifiDisconnectReported {
-    enum FailureCode {
-        UNKNOWN = 0;
-
-        // Wifi supplicant failure reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45).
-        // See ISupplicantStaIfaceCallback.java:ReasonCode
-        UNSPECIFIED = 1;
-        PREV_AUTH_NOT_VALID = 2;
-        DEAUTH_LEAVING = 3;
-        DISASSOC_DUE_TO_INACTIVITY = 4;
-        DISASSOC_AP_BUSY = 5;
-        CLASS2_FRAME_FROM_NONAUTH_STA = 6;
-        CLASS3_FRAME_FROM_NONASSOC_STA = 7;
-        DISASSOC_STA_HAS_LEFT = 8;
-        STA_REQ_ASSOC_WITHOUT_AUTH = 9;
-        PWR_CAPABILITY_NOT_VALID = 10;
-        SUPPORTED_CHANNEL_NOT_VALID = 11;
-        BSS_TRANSITION_DISASSOC = 12;
-        INVALID_IE = 13;
-        MICHAEL_MIC_FAILURE = 14;
-        FOURWAY_HANDSHAKE_TIMEOUT = 15;
-        GROUP_KEY_UPDATE_TIMEOUT = 16;
-        IE_IN_4WAY_DIFFERS = 17;
-        GROUP_CIPHER_NOT_VALID = 18;
-        PAIRWISE_CIPHER_NOT_VALID = 19;
-        AKMP_NOT_VALID = 20;
-        UNSUPPORTED_RSN_IE_VERSION = 21;
-        INVALID_RSN_IE_CAPAB = 22;
-        IEEE_802_1X_AUTH_FAILED = 23;
-        CIPHER_SUITE_REJECTED = 24;
-        TDLS_TEARDOWN_UNREACHABLE = 25;
-        TDLS_TEARDOWN_UNSPECIFIED = 26;
-        SSP_REQUESTED_DISASSOC = 27;
-        NO_SSP_ROAMING_AGREEMENT = 28;
-        BAD_CIPHER_OR_AKM = 29;
-        NOT_AUTHORIZED_THIS_LOCATION = 30;
-        SERVICE_CHANGE_PRECLUDES_TS = 31;
-        UNSPECIFIED_QOS_REASON = 32;
-        NOT_ENOUGH_BANDWIDTH = 33;
-        DISASSOC_LOW_ACK = 34;
-        EXCEEDED_TXOP = 35;
-        STA_LEAVING = 36;
-        END_TS_BA_DLS = 37;
-        UNKNOWN_TS_BA = 38;
-        TIMEOUT = 39;
-        PEERKEY_MISMATCH = 45;
-        AUTHORIZED_ACCESS_LIMIT_REACHED = 46;
-        EXTERNAL_SERVICE_REQUIREMENTS = 47;
-        INVALID_FT_ACTION_FRAME_COUNT = 48;
-        INVALID_PMKID = 49;
-        INVALID_MDE = 50;
-        INVALID_FTE = 51;
-        MESH_PEERING_CANCELLED = 52;
-        MESH_MAX_PEERS = 53;
-        MESH_CONFIG_POLICY_VIOLATION = 54;
-        MESH_CLOSE_RCVD = 55;
-        MESH_MAX_RETRIES = 56;
-        MESH_CONFIRM_TIMEOUT = 57;
-        MESH_INVALID_GTK = 58;
-        MESH_INCONSISTENT_PARAMS = 59;
-        MESH_INVALID_SECURITY_CAP = 60;
-        MESH_PATH_ERROR_NO_PROXY_INFO = 61;
-        MESH_PATH_ERROR_NO_FORWARDING_INFO = 62;
-        MESH_PATH_ERROR_DEST_UNREACHABLE = 63;
-        MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64;
-        MESH_CHANNEL_SWITCH_REGULATORY_REQ = 65;
-        MESH_CHANNEL_SWITCH_UNSPECIFIED = 66;
-
-        // ClientModeImpl error codes
-        // Defined in /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
-        IFACE_DESTROYED = 10000;
-        WIFI_DISABLED = 10001;
-        SUPPLICANT_DISCONNECTED = 10002;
-        CONNECTING_WATCHDOG_TIMER = 10003;
-        ROAM_WATCHDOG_TIMER = 10004;
-    }
-
-    // How long the session lasted from successful connection to disconnect.
-    optional int32 connected_duration_seconds = 1;
-
-    // Reason for the disconnect.
-    optional FailureCode failure_code = 2;
-
-    // Band bucket the connected network was on.
-    optional android.net.wifi.WifiBandBucket band = 3;
-
-    // Authentication type.
-    optional android.net.wifi.WifiAuthType auth_type = 4;
-
-    // Last seen RSSI before the disconnect.
-    optional int32 last_rssi = 5;
-
-    // Last seen link speed before the disconnect.
-    optional int32 last_link_speed = 6;
-}
-
-/**
- * Logs when Wifi connection is established or dropped.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
- */
-message WifiConnectionStateChanged {
-    optional bool is_connected = 1;
-
-    // Band bucket the connected network was on.
-    // Filled for both connected and disconnected cases.
-    optional android.net.wifi.WifiBandBucket band = 2;
-
-    // Authentication type.
-    // Filled for both connected and disconnected cases.
-    optional android.net.wifi.WifiAuthType auth_type = 3;
-}
-
-/**
- * Logs when memory stats of a process is reported.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
- */
-message ProcessMemoryStatReported {
-    optional int32 uid = 1;
-    optional string process_name = 2;
-    optional string package_name = 3;
-    //TODO: remove this when validation is done
-    optional int64 version = 9;
-    optional int64 pss = 4;
-    optional int64 uss = 5;
-    optional int64 rss = 6;
-    enum Type {
-        ADD_PSS_INTERNAL_SINGLE = 0;
-        ADD_PSS_INTERNAL_ALL_MEM = 1;
-        ADD_PSS_INTERNAL_ALL_POLL = 2;
-        ADD_PSS_EXTERNAL = 3;
-        ADD_PSS_EXTERNAL_SLOW = 4;
-    }
-    optional Type type = 7;
-    optional int64 duration_millis = 8;
-}
-
-/**
- * Logs that a process started, finished, crashed, or ANRed.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ProcessLifeCycleStateChanged {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name (usually same as the app name).
-    optional string process_name = 2;
-
-    // What lifecycle state the process changed to.
-    // This enum is specific to atoms.proto.
-    enum State {
-        FINISHED = 0;
-        STARTED = 1;
-        CRASHED = 2;
-    }
-    optional State state = 3;
-}
-
-/**
- * Logs when the ble scan state changes.
- *
- * Logged from:
- *   packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
- */
-message BleScanStateChanged {
-    repeated AttributionNode attribution_node = 1
-            [(state_field_option).primary_field_first_uid = true];
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-        // RESET indicates all ble stopped. Used when it (re)starts (e.g. after it crashes).
-        RESET = 2;
-    }
-    optional State state = 2 [
-        (state_field_option).exclusive_state = true,
-        (state_field_option).default_state_value = 0 /* State.OFF */,
-        (state_field_option).trigger_state_reset_value = 2 /* State.RESET */,
-        (state_field_option).nested = true
-    ];
-
-    // Does the scan have a filter.
-    optional bool is_filtered = 3 [(state_field_option).primary_field = true];
-    // Whether the scan is a CALLBACK_TYPE_FIRST_MATCH scan. Called 'background' scan internally.
-    optional bool is_first_match = 4 [(state_field_option).primary_field = true];
-    // Whether the scan set to piggy-back off the results of other scans (SCAN_MODE_OPPORTUNISTIC).
-    optional bool is_opportunistic = 5 [(state_field_option).primary_field = true];
-}
-
-/**
- * Logs reporting of a ble scan finding results.
- *
- * Logged from:
- *   packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
- */
-// TODO: Consider also tracking per-scanner-id.
-message BleScanResultReceived {
-    repeated AttributionNode attribution_node = 1;
-
-    // Number of ble scan results returned.
-    optional int32 num_results = 2;
-}
-
-/**
- * Logs when a sensor state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message SensorStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    // The id (int) of the sensor.
-    optional int32 sensor_id = 2;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 3;
-}
-
-/**
- * Logs when GPS state changes.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message GpsScanStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs when GPS signal quality.
- *
- * Logged from:
- *   /frameworks/base/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
- */
-message GpsSignalQualityChanged {
-    optional android.server.location.GpsSignalQualityEnum level = 1;
-}
-
-
-/**
- * Logs when a sync manager sync state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message SyncStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    // Name of the sync (as named in the app). Can be chosen at run-time.
-    optional string sync_name = 2;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 3;
-}
-
-/*
- * Deferred job stats.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java
-*/
-message DeferredJobStatsReported {
-    repeated AttributionNode attribution_node = 1;
-
-    // Number of jobs deferred.
-    optional int32 num_jobs_deferred = 2;
-
-    // Time since the last job runs.
-    optional int64 time_since_last_job_millis = 3;
-}
-
-/**
- * Logs when a job scheduler job state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ScheduledJobStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    // Name of the job (as named in the app)
-    optional string job_name = 2;
-
-    enum State {
-        FINISHED = 0;
-        STARTED = 1;
-        SCHEDULED = 2;
-    }
-    optional State state = 3;
-
-    // The reason a job has stopped.
-    // This is only applicable when the state is FINISHED.
-    // The default value is STOP_REASON_UNKNOWN.
-    optional android.app.job.StopReasonEnum stop_reason = 4;
-
-    // The standby bucket of the app that scheduled the job. These match the framework constants
-    // defined in JobSchedulerService.java with the addition of UNKNOWN using -1, as ACTIVE is
-    // already assigned 0.
-    enum Bucket {
-        UNKNOWN = -1;
-        ACTIVE = 0;
-        WORKING_SET = 1;
-        FREQUENT = 2;
-        RARE = 3;
-        NEVER = 4;
-        RESTRICTED = 5;
-    }
-    optional Bucket standby_bucket = 5 [default = UNKNOWN];
-
-    // The job id (as assigned by the app).
-    optional int32 job_id = 6;
-
-    // One flag for each of the API constraints defined by Jobscheduler. Does not include implcit
-    // constraints as they are always assumed to be set.
-    optional bool has_charging_constraint = 7;
-    optional bool has_battery_not_low_constraint = 8;
-    optional bool has_storage_not_low_constraint = 9;
-    optional bool has_timing_delay_constraint = 10;
-    optional bool has_deadline_constraint = 11;
-    optional bool has_idle_constraint = 12;
-    optional bool has_connectivity_constraint = 13;
-    optional bool has_content_trigger_constraint = 14;
-}
-
-/**
- * Logs when the audio state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message AudioStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-        // RESET indicates all audio stopped. Used when it (re)starts (e.g. after it crashes).
-        RESET = 2;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs when the video codec state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message MediaCodecStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-        // RESET indicates all mediaCodec stopped. Used when it (re)starts (e.g. after it crashes).
-        RESET = 2;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs when the flashlight state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message FlashlightStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-        // RESET indicates all flashlight stopped. Used when it (re)starts (e.g. after it crashes).
-        RESET = 2;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs when the camera state changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message CameraStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-        // RESET indicates all camera stopped. Used when it (re)starts (e.g. after it crashes).
-        RESET = 2;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs that the state of a wakelock (per app and per wakelock name) has changed.
- *
- * Logged from:
- *   TODO
- */
-message WakelockStateChanged {
-    repeated AttributionNode attribution_node = 1
-            [(state_field_option).primary_field_first_uid = true];
-
-    // The type (level) of the wakelock; e.g. a partial wakelock or a full wakelock.
-    // From frameworks/base/core/proto/android/os/enums.proto.
-    optional android.os.WakeLockLevelEnum type = 2 [(state_field_option).primary_field = true];
-
-    // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
-    optional string tag = 3 [(state_field_option).primary_field = true];
-
-    enum State {
-        RELEASE = 0;
-        ACQUIRE = 1;
-        CHANGE_RELEASE = 2;
-        CHANGE_ACQUIRE = 3;
-    }
-    optional State state = 4 [
-        (state_field_option).exclusive_state = true,
-        (state_field_option).default_state_value = 0,
-        (state_field_option).nested = true
-    ];
-}
-
-/**
- * Logs when a partial wakelock is considered 'long' (over 1 min).
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message LongPartialWakelockStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
-    optional string tag = 2;
-
-    // TODO: I have no idea what this is.
-    optional string history_tag = 3;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 4;
-}
-
-/**
- * Logs when the device is interactive, according to the PowerManager Notifier.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/power/Notifier.java
- */
-message InteractiveStateChanged {
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 1;
-}
-
-/**
- * Logs Battery Saver state change.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message BatterySaverModeStateChanged {
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs Doze mode state change.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message DeviceIdleModeStateChanged {
-    optional android.server.DeviceIdleModeEnum state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-
-/**
- * Logs state change of Doze mode including maintenance windows.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message DeviceIdlingModeStateChanged {
-    optional android.server.DeviceIdleModeEnum state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs screen brightness level.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message ScreenBrightnessChanged {
-    // Screen brightness level. Should be in [-1, 255] according to PowerManager.java.
-    optional int32 level = 1;
-}
-
-/**
- * Logs battery level (percent full, from 0 to 100).
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message BatteryLevelChanged {
-    // Battery level. Should be in [0, 100].
-    optional int32 battery_level = 1;
-}
-
-/**
- * Logs change in charging status of the device.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message ChargingStateChanged {
-    // State of the battery, from frameworks/base/core/proto/android/os/enums.proto.
-    optional android.os.BatteryStatusEnum state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs whether the device is plugged in, and what power source it is using.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message PluggedStateChanged {
-    // Whether the device is plugged in, from frameworks/base/core/proto/android/os/enums.proto.
-    optional android.os.BatteryPluggedStateEnum state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs when an app's wakeup alarm fires.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message WakeupAlarmOccurred {
-    repeated AttributionNode attribution_node = 1;
-
-    // Name of the wakeup alarm.
-    optional string tag = 2;
-
-    // Name of source package (for historical reasons, since BatteryStats tracked it).
-    optional string package_name = 3;
-
-    // The App Standby bucket of the app that scheduled the alarm at the time the alarm fired.
-    optional AppStandbyBucketChanged.Bucket app_standby_bucket = 4;
-}
-
-/**
- * Logs when an an app causes the mobile radio to change state.
- * Changing from LOW to MEDIUM or HIGH can be considered the app waking the mobile radio.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
- */
-message MobileRadioPowerStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    // Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
-    optional android.telephony.DataConnectionPowerStateEnum state = 2;
-}
-
-/**
- * Logs when an an app causes the wifi radio to change state.
- * Changing from LOW to MEDIUM or HIGH can be considered the app waking the wifi radio.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
- */
-message WifiRadioPowerStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    // Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
-    optional android.telephony.DataConnectionPowerStateEnum state = 2;
-}
-
-/**
- * Logs kernel wakeup reasons and aborts.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message KernelWakeupReported {
-    // Name of the kernel wakeup reason (or abort).
-    optional string wakeup_reason_name = 1;
-
-    // Duration (in microseconds) for the wake-up interrupt to be serviced.
-    optional int64 duration_micros = 2;
-}
-
-/**
- * Logs when Wifi is toggled on/off.
- * Note that Wifi may still perform certain functions (e.g. location scanning) even when disabled.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message WifiEnabledStateChanged {
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 1;
-}
-
-/**
- * This atom is deprecated starting in R.
- *
- * Logs when an app causes Wifi to run. In this context, 'to run' means to use Wifi Client Mode.
- * TODO: Include support for Hotspot, perhaps by using an extra field to denote 'mode'.
- * Note that Wifi Scanning is monitored separately in WifiScanStateChanged.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
- */
-message WifiRunningStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs wifi locks held by an app.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message WifiLockStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 2;
-
-    // WifiLock type, from frameworks/base/core/proto/android/wifi/enums.proto.
-    optional android.net.wifi.WifiModeEnum mode = 3;
-}
-
-/**
- * Logs wifi signal strength changes.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java
- */
-message WifiSignalStrengthChanged {
-    // Signal strength, from frameworks/base/core/proto/android/telephony/enums.proto.
-    optional android.telephony.SignalStrengthEnum signal_strength = 1;
-}
-
-/**
- * Logs wifi scans performed by an app.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
- */
-message WifiScanStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs wifi multicast locks held by an app
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMulticastLockManager.java
- */
-message WifiMulticastLockStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 2;
-
-    optional string tag = 3;
-}
-
-/**
- * Logs shutdown reason and duration on next boot.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/server/BootReceiver.java
- */
-message ShutdownSequenceReported {
-    // True if shutdown is for a reboot. Default: false if we do not know.
-    optional bool reboot = 1;
-
-    // Reason for shutdown. Eg: userrequested. Default: "<EMPTY>".
-    optional string reason = 2;
-
-    // Beginning of shutdown time in ms using wall clock time since unix epoch.
-    // Default: 0 if no start time received.
-    optional int64 start_time_millis = 3;
-
-    // Duration of shutdown in ms. Default: 0 if no duration received.
-    optional int64 duration_millis = 4;
-}
-
-
-/**
- * Logs boot reason and duration.
- *
- * Logged from:
- *   system/core/bootstat/bootstat.cpp
- */
-message BootSequenceReported {
-    // Reason for bootloader boot. Eg. reboot. See bootstat.cpp for larger list
-    // Default: "<EMPTY>" if not available.
-    optional string bootloader_reason = 1;
-
-    // Reason for system boot. Eg. bootloader, reboot,userrequested
-    // Default: "<EMPTY>" if not available.
-    optional string system_reason = 2;
-
-    // End of boot time in ms from unix epoch using system wall clock.
-    optional int64 end_time_millis = 3;
-
-    // Total boot duration in ms.
-    optional int64 total_duration_millis = 4;
-
-    // Bootloader duration in ms.
-    optional int64 bootloader_duration_millis = 5;
-
-    // Time since last boot in ms. Default: 0 if not available.
-    optional int64 time_since_last_boot = 6;
-}
-
-
-/**
- * Logs call state and disconnect cause (if applicable).
- *
- * Logged from:
- *   packages/services/Telecomm/src/com/android/server/telecom/Call.java
- */
-message CallStateChanged {
-    // The state of the call. Eg. DIALING, ACTIVE, ON_HOLD, DISCONNECTED.
-    // From frameworks/base/core/proto/android/telecomm/enums.proto.
-    optional android.telecom.CallStateEnum call_state = 1;
-
-    // The reason the call disconnected. Eg. ERROR, MISSED, REJECTED, BUSY.
-    // This value is only applicable when the call_state is DISCONNECTED, and
-    // should always be UNKNOWN if the call_state is not DISCONNECTED.
-    // From frameworks/base/core/proto/android/telecomm/enums.proto.
-    optional android.telecom.DisconnectCauseEnum disconnect_cause = 2;
-
-    // True if the call is self-managed, which are apps that use the
-    // telecom infrastructure to make their own calls.
-    optional bool self_managed = 3;
-
-    // True if call is external. External calls are calls on connected Wear
-    // devices but show up in Telecom so the user can pull them onto the device.
-    optional bool external_call = 4;
-}
-
-/**
- * Logs keyguard state. The keyguard is the lock screen.
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
- */
-message KeyguardStateChanged {
-    enum State {
-        UNKNOWN = 0;
-        // The keyguard is hidden when the phone is unlocked.
-        HIDDEN = 1;
-        // The keyguard is shown when the phone is locked (screen turns off).
-        SHOWN= 2;
-        // The keyguard is occluded when something is overlaying the keyguard.
-        // Eg. Opening the camera while on the lock screen.
-        OCCLUDED = 3;
-    }
-    optional State state = 1;
-}
-
-/**
- * Logs keyguard bouncer state. The bouncer is a part of the keyguard, and
- * prompts the user to enter a password (pattern, pin, etc).
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
- */
-
-message KeyguardBouncerStateChanged {
-    enum State {
-        UNKNOWN = 0;
-        // Bouncer is hidden, either as a result of successfully entering the
-        // password, screen timing out, or user going back to lock screen.
-        HIDDEN = 1;
-        // This is when the user is being prompted to enter the password.
-        SHOWN = 2;
-    }
-    optional State state = 1;
-}
-
-/**
- * Logs the result of entering a password into the keyguard bouncer.
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
- */
-message KeyguardBouncerPasswordEntered {
-    enum BouncerResult {
-        UNKNOWN = 0;
-        // The password entered was incorrect.
-        FAILURE = 1;
-        // The password entered was correct.
-        SUCCESS = 2;
-    }
-    optional BouncerResult result = 1;
-}
-
-/*
- * Logs changes to the configuration of the device. The configuration is defined
- * in frameworks/base/core/java/android/content/res/Configuration.java
- * More documentation is at https://d.android.com/reference/android/content/res/Configuration.html
- * Please go there to interpret the possible values each field can be.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message ResourceConfigurationChanged {
-    // Bit mask of color capabilities of the screen.
-    // Contains information about the color gamut and hdr mode of the screen.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#colorMode
-    optional int32 color_mode = 1;
-
-    // The target screen density being rendered to.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#densityDpi
-    optional int32 density_dpi = 2;
-
-    // Current user preference for the scaling factor for fonts,
-    // relative to the base density scaling.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#fontScale
-    optional float font_scale = 3;
-
-    // Flag indicating whether the hard keyboard is hidden.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#hardKeyboardHidden
-    optional int32 hard_keyboard_hidden = 4;
-
-    // The type of keyboard attached to the device.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#keyboard
-    optional int32 keyboard = 5;
-
-    // Flag indicating whether any keyboard is available. Takes soft keyboards into account.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#keyboardHidden
-    optional int32 keyboard_hidden = 6;
-
-    // IMSI MCC (Mobile Country Code), corresponding to mcc resource qualifier.
-    // 0 if undefined.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#mcc
-    optional int32 mcc = 7;
-
-    // IMSI MNC (Mobile Network Code), corresponding to mnc resource qualifier.
-    // 0 if undefined. Note: the actual MNC may be 0, to check for this use the
-    // MNC_ZERO symbol defined in Configuration.java.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#mnc
-    optional int32 mnc = 8;
-
-    // The kind of navigation available on the device.
-    // See: https://developer.android.com/reference/android/content/res/Configuration.html#navigation
-    optional int32 navigation = 9;
-
-    // Flag indicating whether the navigation is available.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#navigationHidden
-    optional int32 navigation_hidden = 10;
-
-    // Overall orientation of the screen.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#orientation
-    optional int32 orientation = 11;
-
-    // The current height of the available screen space, in dp units.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#screenHeightDp
-    optional int32 screen_height_dp = 12;
-
-    // Bit mask of overall layout of the screen.
-    // Contains information about screen size, whether the screen is wider/taller
-    // than normal, whether the screen layout is right-tl-left or left-to-right,
-    // and whether the screen has a rounded shape.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#screenLayout
-    optional int32 screen_layout = 13;
-
-    // Current width of the available screen space, in dp units.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#screenWidthDp
-    optional int32 screen_width_dp = 14;
-
-    // The smallest screen size an application will see in normal operation.
-    // This is the smallest value of both screenWidthDp and screenHeightDp
-    // in portrait and landscape.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#smallestScreenWidthDp
-    optional int32 smallest_screen_width_dp = 15;
-
-    // The type of touch screen attached to the device.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#touchscreen
-    optional int32 touchscreen = 16;
-
-    // Bit mask of the ui mode.
-    // Contains information about the overall ui mode of the device.
-    // Eg: NORMAL, DESK, CAR, TELEVISION, WATCH, VR_HEADSET
-    // Also contains information about whether the device is in night mode.
-    // See: https://d.android.com/reference/android/content/res/Configuration.html#uiMode
-    optional int32 ui_mode = 17;
-}
-
-
-/**
- * Logs changes in the connection state of the mobile radio.
- *
- * Logged from:
- *    frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
- */
-message MobileConnectionStateChanged {
-    // States are from the state machine DataConnection.java.
-    enum State {
-        UNKNOWN = 0;
-        // The connection is inactive, or disconnected.
-        INACTIVE = 1;
-        // The connection is being activated, or connecting.
-        ACTIVATING = 2;
-        // The connection is active, or connected.
-        ACTIVE = 3;
-        // The connection is disconnecting.
-        DISCONNECTING = 4;
-        // The connection is disconnecting after creating a connection.
-        DISCONNECTION_ERROR_CREATING_CONNECTION = 5;
-    }
-    optional State state  = 1;
-    // For multi-sim phones, this distinguishes between the sim cards.
-    optional int32 sim_slot_index = 2;
-    // Used to identify the connection. Starts at 0 and increments by 1 for
-    // every new network created. Resets whenever the device reboots.
-    optional int32 data_connection_id = 3;
-    // A bitmask for the capabilities of this connection.
-    // Eg. DEFAULT (internet), MMS, SUPL, DUN, IMS.
-    // Default value (if we have no information): 0
-    optional int64 capabilities = 4;
-    // If this connection has internet.
-    // This just checks if the DEFAULT bit of capabilities is set.
-    optional bool has_internet = 5;
-}
-
-/**
- * Logs changes in mobile radio technology. eg: LTE, EDGE, CDMA.
- *
- * Logged from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
- */
-message MobileRadioTechnologyChanged {
-    optional android.telephony.NetworkTypeEnum state = 1;
-    // For multi-sim phones, this distinguishes between the sim cards.
-    optional int32 sim_slot_index = 2;
-}
-
-/**
- * Logs the VID and PID of any connected USB devices.
- *
- * Notes if any Audio, HID (input buttons/mouse/keyboard), or Storage interfaces are present.
- *
- * Logged by Vendor.
- */
-message UsbDeviceAttached {
-    optional int32 vid = 1;
-    optional int32 pid = 2;
-    optional bool has_audio = 3;
-    optional bool has_hid = 4;
-    optional bool has_storage = 5;
-    enum State {
-        STATE_DISCONNECTED = 0;
-        STATE_CONNECTED = 1;
-    }
-    optional State state = 6;
-    optional int64 last_connect_duration_millis = 7;
-}
-
-
-/**
- * Logs when Bluetooth is enabled and disabled.
- *
- * Logged from:
- *   services/core/java/com/android/server/BluetoothManagerService.java
- */
-message BluetoothEnabledStateChanged {
-    repeated AttributionNode attribution_node = 1;
-    // Whether or not bluetooth is enabled on the device.
-    enum State {
-        UNKNOWN = 0;
-        ENABLED = 1;
-        DISABLED = 2;
-    }
-    optional State state = 2;
-    // The reason for being enabled/disabled.
-    // Eg. Airplane mode, crash, application request.
-    optional android.bluetooth.EnableDisableReasonEnum reason = 3;
-    // If the reason is an application request, this will be the package name.
-    optional string pkg_name = 4;
-}
-
-/**
- * Logs when profiles on a Bluetooth device connects and disconnects.
- *
- * Logged from:
- *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
- *
- * Next Tag: 6
- */
-message BluetoothConnectionStateChanged {
-    // The state of the connection.
-    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
-    optional android.bluetooth.ConnectionStateEnum state = 1;
-    // An identifier that can be used to match connect and disconnect events.
-    // Currently is last two bytes of a hash of a device level ID and
-    // the mac address of the bluetooth device that is connected.
-    // Deprecated: use obfuscated_id instead, this one is always 0 for Q+
-    optional int32 obfuscated_id = 2 [deprecated = true];
-    // The profile that is connected. Eg. GATT, A2DP, HEADSET.
-    // From android.bluetooth.BluetoothAdapter.java
-    // Default: 0 when not used
-    optional int32 bt_profile = 3;
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes new_obfuscated_id = 4 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 5;
-}
-
-/**
- * Logs when a Bluetooth device connects and disconnects over ACL
- *
- * Logged from:
- *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
- *
- * Next Tag: 4
- */
-message BluetoothAclConnectionStateChanged {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // The state of the connection.
-    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
-    optional android.bluetooth.ConnectionStateEnum state = 2;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 3;
-}
-
-/**
- * Logs when a Bluetooth device connects and disconnects over SCO
- *
- * Logged from:
- *    packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
- *    packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetClientStateMachine.java
- *
- * Next Tag: 5
- */
-message BluetoothScoConnectionStateChanged {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // The state of the connection.
-    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
-    optional android.bluetooth.ConnectionStateEnum state = 2;
-    // Codec used for this SCO connection
-    // Default: UNKNOWN
-    optional android.bluetooth.hfp.ScoCodec codec = 3;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 4;
-}
-
-/**
- * Logged when active device of a profile changes
- *
- * Logged from:
- *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
- *     packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java
- *     packages/apps/Bluetooth/src/com/android/bluetooth/hearingaid/HearingAidService.java
- */
-message BluetoothActiveDeviceChanged {
-    // The profile whose active device has changed. Eg. A2DP, HEADSET, HEARING_AID
-    // From android.bluetooth.BluetoothProfile
-    optional int32 bt_profile = 1;
-    // An identifier that can be used to match events for this new active device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if there is no active device for this profile
-    optional bytes obfuscated_id = 2 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 3;
-}
-
-// Logs when there is an event affecting Bluetooth device's link layer connection.
-// - This event is triggered when there is a related HCI command or event
-// - Users of this metrics can deduce Bluetooth device's connection state from these events
-// - HCI commands are logged before the command is sent, after receiving command status, and after
-//   receiving command complete
-// - HCI events are logged when they arrive
-//
-// Low level log from system/bt
-//
-// Bluetooth classic commands:
-// - CMD_CREATE_CONNECTION
-// - CMD_DISCONNECT
-// - CMD_CREATE_CONNECTION_CANCEL
-// - CMD_ACCEPT_CONNECTION_REQUEST
-// - CMD_REJECT_CONNECTION_REQUEST
-// - CMD_SETUP_ESCO_CONNECTION
-// - CMD_ACCEPT_ESCO_CONNECTION
-// - CMD_REJECT_ESCO_CONNECTION
-// - CMD_ENH_SETUP_ESCO_CONNECTION
-// - CMD_ENH_ACCEPT_ESCO_CONNECTION
-//
-// Bluetooth low energy commands:
-// - CMD_BLE_CREATE_LL_CONN [Only logged on error or when initiator filter policy is 0x00]
-// - CMD_BLE_CREATE_CONN_CANCEL [Only logged when there is an error]
-// - CMD_BLE_EXTENDED_CREATE_CONNECTION [Only logged on error or when initiator filter policy is 0x00]
-// - CMD_BLE_CLEAR_WHITE_LIST
-// - CMD_BLE_ADD_WHITE_LIST
-// - CMD_BLE_REMOVE_WHITE_LIST
-//
-// Bluetooth classic events:
-// - EVT_CONNECTION_COMP
-// - EVT_CONNECTION_REQUEST
-// - EVT_DISCONNECTION_COMP
-// - EVT_ESCO_CONNECTION_COMP
-// - EVT_ESCO_CONNECTION_CHANGED
-//
-// Bluetooth low energy meta events:
-// - BLE_EVT_CONN_COMPLETE_EVT
-// - BLE_EVT_ENHANCED_CONN_COMPLETE_EVT
-//
-// Next tag: 10
-message BluetoothLinkLayerConnectionEvent {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Connection handle of this connection if available
-    // Range: 0x0000 - 0x0EFF (12 bits)
-    // Default: 0xFFFF if the handle is unknown
-    optional int32 connection_handle = 2;
-    // Direction of the link
-    // Default: DIRECTION_UNKNOWN
-    optional android.bluetooth.DirectionEnum direction = 3;
-    // Type of this link
-    // Default: LINK_TYPE_UNKNOWN
-    optional android.bluetooth.LinkTypeEnum type = 4;
-
-    // Reason metadata for this link layer connection event, rules for interpretation:
-    // 1. If hci_cmd is set and valid, hci_event can be either EVT_COMMAND_STATUS or
-    //    EVT_COMMAND_COMPLETE, ignore hci_ble_event in this case
-    // 2. If hci_event is set to EVT_BLE_META, look at hci_ble_event; otherwise, if hci_event is
-    //    set and valid, ignore hci_ble_event
-
-    // HCI command associated with this event
-    // Default: CMD_UNKNOWN
-    optional android.bluetooth.hci.CommandEnum hci_cmd = 5;
-    // HCI event associated with this event
-    // Default: EVT_UNKNOWN
-    optional android.bluetooth.hci.EventEnum hci_event = 6;
-    // HCI BLE meta event associated with this event
-    // Default: BLE_EVT_UNKNOWN
-    optional android.bluetooth.hci.BleMetaEventEnum hci_ble_event = 7;
-    // HCI command status code if this is triggerred by hci_cmd
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum cmd_status = 8;
-    // HCI reason code associated with this event
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum reason_code = 9;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 10;
-}
-
-/**
- * Logs when a module is rolled back by Watchdog.
- *
- * Logged from: Rollback Manager
- */
-message WatchdogRollbackOccurred {
-    enum RollbackType {
-        UNKNOWN = 0;
-        ROLLBACK_INITIATE = 1;
-        ROLLBACK_SUCCESS = 2;
-        ROLLBACK_FAILURE = 3;
-        ROLLBACK_BOOT_TRIGGERED = 4;
-    }
-    optional RollbackType rollback_type = 1;
-
-    optional string package_name = 2;
-
-    optional int32 package_version_code = 3;
-
-    enum RollbackReasonType {
-        REASON_UNKNOWN = 0;
-        REASON_NATIVE_CRASH = 1;
-        REASON_EXPLICIT_HEALTH_CHECK = 2;
-        REASON_APP_CRASH = 3;
-        REASON_APP_NOT_RESPONDING = 4;
-        REASON_NATIVE_CRASH_DURING_BOOT = 5;
-    }
-    optional RollbackReasonType rollback_reason = 4;
-
-    // Set by RollbackPackageHealthObserver to be the package that is failing when a rollback
-    // is initiated. Empty if the package is unknown.
-    optional string failing_package_name = 5;
-
-    optional TrainExperimentIds experiment_ids = 6 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs when there is a change in Bluetooth A2DP playback state
- *
- * Logged from:
- *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
- */
-message BluetoothA2dpPlaybackStateChanged {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Current playback state
-    // Default: PLAYBACK_STATE_UNKNOWN
-    optional android.bluetooth.a2dp.PlaybackStateEnum playback_state = 2;
-    // Current audio coding mode
-    // Default: AUDIO_CODING_MODE_UNKNOWN
-    optional android.bluetooth.a2dp.AudioCodingModeEnum audio_coding_mode = 3;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 4;
-}
-
-/**
- * Logs when there is a change in A2DP codec config for a particular remote device
- *
- * Logged from:
- *     frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java
- *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
- */
-message BluetoothA2dpCodecConfigChanged {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig
-    // Default SOURCE_CODEC_TYPE_INVALID
-    optional int32 codec_type = 2;
-    // Codec priroity, the higher the more preferred, -1 for disabled
-    // Default: CODEC_PRIORITY_DEFAULT
-    optional int32 codec_priority = 3;
-    // Sample rate in Hz as defined by various SAMPLE_RATE_* constants in BluetoothCodecConfig
-    // Default: SAMPLE_RATE_NONE
-    optional int32 sample_rate = 4;
-    // Bits per sample as defined by various BITS_PER_SAMPLE_* constants in BluetoothCodecConfig
-    // Default: BITS_PER_SAMPLE_NONE
-    optional int32 bits_per_sample = 5;
-    // Channel mode as defined by various CHANNEL_MODE_* constants in BluetoothCodecConfig
-    // Default: CHANNEL_MODE_NONE
-    optional int32 channel_mode = 6;
-    // Codec specific values
-    // Default 0
-    optional int64 codec_specific_1 = 7;
-    optional int64 codec_specific_2 = 8;
-    optional int64 codec_specific_3 = 9;
-    optional int64 codec_specific_4 = 10;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 11;
-}
-
-/**
- * Logs when there is a change in selectable A2DP codec capability for a paricular remote device
- * Each codec's capability is logged separately due to statsd restriction
- *
- * Logged from:
- *     frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java
- *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
- */
-message BluetoothA2dpCodecCapabilityChanged {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig
-    // Default SOURCE_CODEC_TYPE_INVALID
-    optional int32 codec_type = 2;
-    // Codec priroity, the higher the more preferred, -1 for disabled
-    // Default: CODEC_PRIORITY_DEFAULT
-    optional int32 codec_priority = 3;
-    // A bit field of supported sample rates as defined by various SAMPLE_RATE_* constants
-    // in BluetoothCodecConfig
-    // Default: empty and SAMPLE_RATE_NONE for individual item
-    optional int32 sample_rate = 4;
-    // A bit field of supported bits per sample as defined by various BITS_PER_SAMPLE_* constants
-    // in BluetoothCodecConfig
-    // Default: empty and BITS_PER_SAMPLE_NONE for individual item
-    optional int32 bits_per_sample = 5;
-    // A bit field of supported channel mode as defined by various CHANNEL_MODE_* constants in
-    // BluetoothCodecConfig
-    // Default: empty and CHANNEL_MODE_NONE for individual item
-    optional int32 channel_mode = 6;
-    // Codec specific values
-    // Default 0
-    optional int64 codec_specific_1 = 7;
-    optional int64 codec_specific_2 = 8;
-    optional int64 codec_specific_3 = 9;
-    optional int64 codec_specific_4 = 10;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 11;
-}
-
-/**
- * Logs when A2DP failed to read from PCM source.
- * This typically happens when audio HAL cannot supply A2DP with data fast enough for encoding.
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothA2dpAudioUnderrunReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Encoding interval in nanoseconds
-    // Default: 0
-    optional int64 encoding_interval_nanos = 2;
-    // Number of bytes of PCM data that could not be read from the source
-    // Default: 0
-    optional int32 num_missing_pcm_bytes = 3;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 4;
-}
-
-/**
- * Logs when A2DP failed send encoded data to the remote device fast enough such that the transmit
- * buffer queue is full and we have to drop data
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothA2dpAudioOverrunReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Encoding interval in nanoseconds
-    // Default: 0
-    optional int64 encoding_interval_nanos = 2;
-    // Number of buffers dropped in this event
-    // Each buffer is encoded in one encoding interval and consists of multiple encoded frames
-    // Default: 0
-    optional int32 num_dropped_buffers = 3;
-    // Number of encoded buffers dropped in this event
-    // Default 0
-    optional int32 num_dropped_encoded_frames = 4;
-    // Number of encoded bytes dropped in this event
-    // Default: 0
-    optional int32 num_dropped_encoded_bytes = 5;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 6;
-}
-
-/**
- * Logs when we receive reports regarding a device's RSSI value
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothDeviceRssiReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Connection handle of this connection if available
-    // Range: 0x0000 - 0x0EFF (12 bits)
-    // Default: 0xFFFF if the handle is unknown
-    optional int32 connection_handle = 2;
-    // HCI command status code if this is triggerred by hci_cmd
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum hci_status = 3;
-    // BR/EDR
-    //   Range: -128 ≤ N ≤ 127 (signed integer)
-    //   Units: dB
-    // LE:
-    //   Range: -127 to 20, 127 (signed integer)
-    //   Units: dBm
-    // Invalid when an out of range value is reported
-    optional int32 rssi = 4;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 5;
-}
-
-/**
- * Logs when we receive reports regarding how many consecutive failed contacts for a connection
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothDeviceFailedContactCounterReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Connection handle of this connection if available
-    // Range: 0x0000 - 0x0EFF (12 bits)
-    // Default: 0xFFFF if the handle is unknown
-    optional int32 connection_handle = 2;
-    // HCI command status code if this is triggerred by hci_cmd
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum cmd_status = 3;
-    // Number of consecutive failed contacts for a connection corresponding to the Handle
-    // Range: uint16_t, 0-0xFFFF
-    // Default: 0xFFFFF
-    optional int32 failed_contact_counter = 4;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 5;
-}
-
-/**
- * Logs when we receive reports regarding the tranmit power level used for a specific connection
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothDeviceTxPowerLevelReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Connection handle of this connection if available
-    // Range: 0x0000 - 0x0EFF (12 bits)
-    // Default: 0xFFFF if the handle is unknown
-    optional int32 connection_handle = 2;
-    // HCI command status code if this is triggered by hci_cmd
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum hci_status = 3;
-    // Range: -30 ≤ N ≤ 20
-    // Units: dBm
-    // Invalid when an out of range value is reported
-    optional int32 transmit_power_level = 4;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 5;
-}
-
-/**
- * Logs when Bluetooth controller failed to reply with command status within a timeout period after
- * receiving an HCI command from the host
- *
- * Logged from: system/bt
- */
-message BluetoothHciTimeoutReported {
-    // HCI command associated with this event
-    // Default: CMD_UNKNOWN
-    optional android.bluetooth.hci.CommandEnum hci_command = 1;
-}
-
-/**
- * Logs when we receive Bluetooth Link Quality Report event from the controller
- * See Android Bluetooth HCI specification for more details
- *
- * Note: all count and bytes field are counted since last event
- *
- * Logged from: system/bt
- */
-message BluetoothQualityReportReported {
-    // Quality report ID
-    // Original type: uint8_t
-    // Default: BQR_ID_UNKNOWN
-    optional android.bluetooth.hci.BqrIdEnum quality_report_id = 1;
-    // Packet type of the connection
-    // Original type: uint8_t
-    // Default: BQR_PACKET_TYPE_UNKNOWN
-    optional android.bluetooth.hci.BqrPacketTypeEnum packet_types = 2;
-    // Connection handle of the connection
-    // Original type: uint16_t
-    optional int32 connection_handle = 3;
-    // Performing Role for the connection
-    // Original type: uint8_t
-    optional int32 connection_role = 4;
-    // Current Transmit Power Level for the connection. This value is the same as the controller's
-    // response to the HCI_Read_Transmit_Power_Level HCI command
-    // Original type: uint8_t
-    optional int32 tx_power_level = 5;
-    // Received Signal Strength Indication (RSSI) value for the connection. This value is an
-    // absolute receiver signal strength value
-    // Original type: int8_t
-    optional int32 rssi = 6;
-    // Signal-to-Noise Ratio (SNR) value for the connection. It is the average SNR of all the
-    // channels used by the link currently
-    // Original type: uint8_t
-    optional int32 snr = 7;
-    // Indicates the number of unused channels in AFH_channel_map
-    // Original type: uint8_t
-    optional int32 unused_afh_channel_count = 8;
-    // Indicates the number of the channels which are interfered and quality is bad but are still
-    // selected for AFH
-    // Original type: uint8_t
-    optional int32 afh_select_unideal_channel_count = 9;
-    // Current Link Supervision Timeout Setting
-    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
-    // Original type: uint16_t
-    optional int32 lsto = 10;
-    // Piconet Clock for the specified Connection_Handle. This value is the same as the controller's
-    // response to HCI_Read_Clock HCI command with the parameter "Which_Clock" of
-    // 0x01 (Piconet Clock)
-    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
-    // Original type: uint32_t
-    optional int64 connection_piconet_clock = 11;
-    // The count of retransmission
-    // Original type: uint32_t
-    optional int64 retransmission_count = 12;
-    // The count of no RX
-    // Original type: uint32_t
-    optional int64 no_rx_count = 13;
-    // The count of NAK (Negative Acknowledge)
-    // Original type: uint32_t
-    optional int64 nak_count = 14;
-    // Controller timestamp of last TX ACK
-    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
-    // Original type: uint32_t
-    optional int64 last_tx_ack_timestamp = 15;
-    // The count of Flow-off (STOP)
-    // Original type: uint32_t
-    optional int64 flow_off_count = 16;
-    // Controller timestamp of last Flow-on (GO)
-    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
-    // Original type: uint32_t
-    optional int64 last_flow_on_timestamp = 17;
-    // Buffer overflow count (how many bytes of TX data are dropped) since the last event
-    // Original type: uint32_t
-    optional int64 buffer_overflow_bytes = 18;
-    // Buffer underflow count (in byte) since last event
-    // Original type: uint32_t
-    optional int64 buffer_underflow_bytes = 19;
-}
-
-/**
- * Logs when a Bluetooth device's manufacturer information is learnt by the Bluetooth stack
- *
- * Notes:
- * - Each event can be partially filled as we might learn different pieces of device
- *   information at different time
- * - Multiple device info events can be combined to give more complete picture
- * - When multiple device info events tries to describe the same information, the
- *   later one wins
- *
- * Logged from:
- *     packages/apps/Bluetooth
- */
-message BluetoothDeviceInfoReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Where is this device info obtained from
-    optional android.bluetooth.DeviceInfoSrcEnum source_type = 2;
-    // Name of the data source
-    // For EXTERNAL: package name of the data source
-    // For INTERNAL: null for general case, component name otherwise
-    optional string source_name = 3;
-    // Name of the manufacturer of this device
-    optional string manufacturer = 4;
-    // Model of this device
-    optional string model = 5;
-    // Hardware version of this device
-    optional string hardware_version = 6;
-    // Software version of this device
-    optional string software_version = 7;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 8;
-}
-
-/**
- * Logs when we receive Bluetooth Read Remote Version Information Complete Event from the remote
- * device, as documented by the Bluetooth Core HCI specification
- * Reference: https://www.bluetooth.com/specifications/bluetooth-core-specification
- * Vol 2, Part E, Page 1118
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothRemoteVersionInfoReported {
-    // Connection handle of the connection
-    // Original type: uint16_t
-    optional int32 connection_handle = 1;
-    // HCI command status code
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum hci_status = 2;
-    // 1 byte Version of current LMP in the remote controller
-    optional int32 lmp_version = 3;
-    // 2 bytes LMP manufacturer code of the remote controller
-    // https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
-    optional int32 lmp_manufacturer_code = 4;
-    // 4 bytes subversion of the LMP in the remote controller
-    optional int32 lmp_subversion = 5;
-}
-
-/**
- * Logs when certain Bluetooth SDP attributes are discovered
- * Constant definitions are from:
- *     https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
- *
- * Current logged attributes:
- * - BluetoothProfileDescriptorList
- * - Supported Features Bitmask
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothSdpAttributeReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Short form UUIDs used to identify Bluetooth protocols, profiles, and service classes
-    // Original type: uint16_t
-    optional int32 protocol_uuid = 2;
-    // Short form UUIDs used to identify Bluetooth SDP attribute types
-    // Original type: uint16_t
-    optional int32 attribute_id = 3;
-    // Attribute value for the particular attribute
-    optional bytes attribute_value = 4 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 5;
-}
-
-/**
- * Logs when bond state of a Bluetooth device changes
- *
- * Logged from:
- *     frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
- *     packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java
- */
-message BluetoothBondStateChanged {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Preferred transport type to remote dual mode device
-    // Default: TRANSPORT_AUTO means no preference
-    optional android.bluetooth.TransportTypeEnum transport = 2;
-    // The type of this Bluetooth device (Classic, LE, or Dual mode)
-    // Default: UNKNOWN
-    optional android.bluetooth.DeviceTypeEnum type = 3;
-    // Current bond state (NONE, BONDING, BONDED)
-    // Default: BOND_STATE_UNKNOWN
-    optional android.bluetooth.BondStateEnum bond_state = 4;
-    // Bonding sub state
-    // Default: BOND_SUB_STATE_UNKNOWN
-    optional android.bluetooth.BondSubStateEnum bonding_sub_state = 5;
-    // Unbond Reason
-    // Default: UNBOND_REASON_UNKNOWN
-    optional android.bluetooth.UnbondReasonEnum unbond_reason = 6;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 7;
-}
-
-/**
- * Logs there is an event related Bluetooth classic pairing
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothClassicPairingEventReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Connection handle of this connection if available
-    // Range: 0x0000 - 0x0EFF (12 bits)
-    // Default: 0xFFFF if the handle is unknown
-    optional int32 connection_handle = 2;
-    // HCI command associated with this event
-    // Default: CMD_UNKNOWN
-    optional android.bluetooth.hci.CommandEnum hci_cmd = 3;
-    // HCI event associated with this event
-    // Default: EVT_UNKNOWN
-    optional android.bluetooth.hci.EventEnum hci_event = 4;
-    // HCI command status code if this is triggerred by hci_cmd
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum cmd_status = 5;
-    // HCI reason code associated with this event
-    // Default: STATUS_UNKNOWN
-    optional android.bluetooth.hci.StatusEnum reason_code = 6;
-    // A status value related to this specific event
-    // Default: 0
-    optional int64 event_value = 7;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 8;
-}
-
-/**
- * Logs when there is an event related to Bluetooth Security Manager Protocol (SMP)
- *
- * Logged from:
- *     system/bt
- */
-message BluetoothSmpPairingEventReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // SMP command sent or received over L2CAP
-    // Default: CMD_UNKNOWN
-    optional android.bluetooth.smp.CommandEnum smp_command = 2;
-    // Whether this command is sent or received
-    // Default: DIRECTION_UNKNOWN
-    optional android.bluetooth.DirectionEnum direction = 3;
-    // SMP failure reason code
-    // Default: PAIRING_FAIL_REASON_DEFAULT
-    optional android.bluetooth.smp.PairingFailReasonEnum smp_fail_reason = 4;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 5;
-}
-
-/**
- * Logs when a Bluetooth socket’s connection state changed
- *
- * Logged from:
- *   system/bt
- */
-message BluetoothSocketConnectionStateChanged {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if this is a server listener socket
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Temporary port of this socket for the current connection or session only
-    // Default 0 when unknown or don't care
-    optional int32 port = 2;
-    // Socket type as mentioned in
-    // frameworks/base/core/java/android/bluetooth/BluetoothSocket.java
-    // Default: SOCKET_TYPE_UNKNOWN
-    optional android.bluetooth.SocketTypeEnum type = 3;
-    // Socket connection state
-    // Default: SOCKET_CONNECTION_STATE_UNKNOWN
-    optional android.bluetooth.SocketConnectionstateEnum state = 4;
-    // Number of bytes sent to remote device during this connection
-    optional int64 tx_bytes = 5;
-    // Number of bytes received from remote device during this connection
-    optional int64 rx_bytes = 6;
-    // Socket owner's UID
-    optional int32 uid = 7 [(is_uid) = true];
-    // Server port of this socket, if any. When both |server_port| and |port| fields are populated,
-    // |port| must be spawned by |server_port|
-    // Default 0 when unknown or don't care
-    optional int32 server_port = 8;
-    // Whether this is a server listener socket
-    optional android.bluetooth.SocketRoleEnum is_server = 9;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 10;
-}
-
-/**
- * Logs when Class of Device (CoD) value is learnt for a device during pairing or connection
- *
- * Logged from:
- *   packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java
- *   packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
- *
- */
-message BluetoothClassOfDeviceReported {
-    // An identifier that can be used to match events for this device.
-    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
-    // Salt: Randomly generated 256 bit value
-    // Hash algorithm: HMAC-SHA256
-    // Size: 32 byte
-    // Default: null or empty if this is a server listener socket
-    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Class of Device (CoD) value including both Major, Minor device class and service class
-    // Defined in: https://www.bluetooth.com/specifications/assigned-numbers/baseband
-    // Also defined in: https://developer.android.com/reference/android/bluetooth/BluetoothClass
-    // Default: 0
-    optional int32 class_of_device = 2;
-    // An identifier that can be used to match events for this device.
-    // The incremental identifier is locally generated and guaranteed not derived
-    // from any globally unique hardware id.
-    // For paired devices, it stays consistent between Bluetooth toggling for the
-    // same remote device.
-    // For unpaired devices, it stays consistent within the same Bluetooth adapter
-    // session for the same remote device.
-    // Default: 0 if the device's metric id is unknown.
-    optional int32 metric_id = 3;
-}
-
-/**
- * Logs when something is plugged into or removed from the USB-C connector.
- *
- * Logged from:
- *  UsbService
- */
-message UsbConnectorStateChanged {
-    enum State {
-        STATE_DISCONNECTED = 0;
-        STATE_CONNECTED = 1;
-    }
-    optional State state = 1
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-    optional string id = 2 [(state_field_option).primary_field = true];
-    // Last active session in ms.
-    // 0 when the port is in connected state.
-    optional int64 last_connect_duration_millis = 3;
-}
-
-/**
- * Logs the reported speaker impedance.
- *
- * Logged from:
- *  Vendor audio implementation.
- */
-message SpeakerImpedanceReported {
-    optional int32 speaker_location = 1;
-    optional int32 impedance = 2;
-}
-
-/**
- * Logs the report of a failed hardware.
- *
- * Logged from:
- *  Vendor HALs.
- *
- */
-message HardwareFailed {
-    enum HardwareType {
-        HARDWARE_FAILED_UNKNOWN = 0;
-        HARDWARE_FAILED_MICROPHONE = 1;
-        HARDWARE_FAILED_CODEC = 2;
-        HARDWARE_FAILED_SPEAKER = 3;
-        HARDWARE_FAILED_FINGERPRINT = 4;
-    }
-    optional HardwareType hardware_type = 1;
-
-   /**
-    * hardware_location allows vendors to differentiate between multiple instances of
-    * the same hardware_type.  The specific locations are vendor defined integers,
-    * referring to board-specific numbering schemes.
-    */
-    optional int32 hardware_location = 2;
-
-    /**
-     * failure_code is specific to the HardwareType of the failed hardware.
-     * It should use one of the enum values defined below.
-     */
-    enum HardwareErrorCode {
-        UNKNOWN = 0;
-        COMPLETE = 1;
-        SPEAKER_HIGH_Z = 2;
-        SPEAKER_SHORT = 3;
-        FINGERPRINT_SENSOR_BROKEN = 4;
-        FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
-        DEGRADE = 6;
-    }
-    optional int32 failure_code = 3;
-}
-
-/**
- * Log an event when the device has been physically dropped.
- * Reported from the /vendor partition.
- */
-message PhysicalDropDetected {
-    // Confidence that the event was actually a drop, 0 -> 100
-    optional int32 confidence_pctg = 1;
-    // Peak acceleration of the drop, in 1/1000s of a g.
-    optional int32 accel_peak_thousandths_g = 2;
-    // Duration of freefall in ms
-    optional int32 freefall_time_millis = 3;
-}
-
-/**
- * Log bucketed battery charge cycles.
- *
- * Each bucket represents cycles of the battery past
- * a given charge point.  For example, if 10 cycle buckets are
- * initialized, bucket 1 is the lowest 1/10th of the battery,
- * and bucket 10 is 100%.
- *
- * Logged from:
- * /sys/class/power_supply/bms/cycle_count, via Vendor.
- */
-message ChargeCyclesReported {
-    optional int32 cycle_bucket_1 = 1;
-    optional int32 cycle_bucket_2 = 2;
-    optional int32 cycle_bucket_3 = 3;
-    optional int32 cycle_bucket_4 = 4;
-    optional int32 cycle_bucket_5 = 5;
-    optional int32 cycle_bucket_6 = 6;
-    optional int32 cycle_bucket_7 = 7;
-    optional int32 cycle_bucket_8 = 8;
-    optional int32 cycle_bucket_9 = 9;
-    optional int32 cycle_bucket_10 = 10;
-}
-
-/**
- * Log battery health snapshot.
- *
- * Resistance, Voltage, Open Circuit Voltage, Temperature, and Charge Level
- * are snapshotted periodically over 24hrs.
- */
-message BatteryHealthSnapshot {
-    enum BatterySnapshotType {
-        UNKNOWN = 0;
-        MIN_TEMP = 1;         // Snapshot at min batt temp over 24hrs.
-        MAX_TEMP = 2;         // Snapshot at max batt temp over 24hrs.
-        MIN_RESISTANCE = 3;   // Snapshot at min batt resistance over 24hrs.
-        MAX_RESISTANCE = 4;   // Snapshot at max batt resistance over 24hrs.
-        MIN_VOLTAGE = 5;      // Snapshot at min batt voltage over 24hrs.
-        MAX_VOLTAGE = 6;      // Snapshot at max batt voltage over 24hrs.
-        MIN_CURRENT = 7;      // Snapshot at min batt current over 24hrs.
-        MAX_CURRENT = 8;      // Snapshot at max batt current over 24hrs.
-        MIN_BATT_LEVEL = 9;   // Snapshot at min battery level (SoC) over 24hrs.
-        MAX_BATT_LEVEL = 10;  // Snapshot at max battery level (SoC) over 24hrs.
-        AVG_RESISTANCE = 11;  // Snapshot at average battery resistance over 24hrs.
-    }
-    optional BatterySnapshotType type = 1;
-    // Temperature, in 1/10ths of degree C.
-    optional int32 temperature_deci_celsius = 2;
-    // Voltage Battery Voltage, in microVolts.
-    optional int32 voltage_micro_volt = 3;
-    // Current Battery current, in microAmps.
-    optional int32 current_micro_amps = 4;
-    // OpenCircuitVoltage Battery Open Circuit Voltage, in microVolts.
-    optional int32 open_circuit_micro_volt = 5;
-    // Resistance Battery Resistance, in microOhms.
-    optional int32 resistance_micro_ohm = 6;
-    // Level Battery Level, as % of full.
-    optional int32 level_percent = 7;
-}
-
-/**
- * Log slow I/O operations on the primary storage.
- */
-message SlowIo {
-    // Classifications of IO Operations.
-    enum IoOperation {
-        UNKNOWN = 0;
-        READ = 1;
-        WRITE = 2;
-        UNMAP = 3;
-        SYNC = 4;
-    }
-    optional IoOperation operation = 1;
-
-    // The number of slow IO operations of this type over 24 hours.
-    optional int32 count = 2;
-}
-
-/**
- * Log battery caused shutdown with the last recorded voltage.
- */
-message BatteryCausedShutdown {
-    // The last recorded battery voltage prior to shutdown.
-    optional int32 last_recorded_micro_volt = 1;
-}
-
-/**
- * Logs when ThermalService receives throttling events.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java
- */
-message ThermalThrottlingSeverityStateChanged {
-    // The type of temperature being reported (CPU, GPU, SKIN, etc)
-    optional android.os.TemperatureTypeEnum sensor_type = 1;
-
-    // The name of the temperature source. Eg. CPU0
-    optional string sensor_name = 2;
-
-    // Temperature in tenths of a degree C.
-    // For BCL, it is decimillivolt, decimilliamps, and percentage * 10.
-    optional int32 temperature_deci_celsius = 3;
-
-    // Relative severity of the throttling, see enum definition.
-    optional android.os.ThrottlingSeverityEnum severity = 4;
-}
-
-/**
- * Logs the duration of a davey (jank of >=700ms) when it occurs
- *
- * Logged from:
- *   frameworks/base/libs/hwui/JankTracker.cpp
- */
-message DaveyOccurred {
-    // The UID that logged this atom.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Amount of time it took to render the frame. Should be >=700ms.
-    optional int64 jank_duration_millis = 2;
-}
-
-/**
- * Logs phone signal strength changes.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message PhoneSignalStrengthChanged {
-    // Signal strength, from frameworks/base/core/proto/android/telephony/enums.proto.
-    optional android.telephony.SignalStrengthEnum signal_strength = 1;
-}
-
-
-/**
- * Logs when the phone state, sim state or signal strength changes
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message PhoneServiceStateChanged {
-    optional android.telephony.ServiceStateEnum state = 1;
-    optional android.telephony.SimStateEnum sim_state = 2;
-    optional android.telephony.SignalStrengthEnum signal_strength = 3;
-}
-
-/**
- * Logs when the phone becomes on or off.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/TelephonyRegistry.java
- */
-message PhoneStateChanged {
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 1;
-}
-
-message BackGesture {
-    enum BackType {
-        DEFAULT_BACK_TYPE = 0;
-        COMPLETED = 1;
-        COMPLETED_REJECTED = 2; // successful because coming from rejected area
-        INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area
-        INCOMPLETE = 4;  // Unsuccessful, for reasons other than below.
-        INCOMPLETE_FAR_FROM_EDGE = 5;  // Unsuccessful, far from the edge.
-        INCOMPLETE_MULTI_TOUCH = 6;  // Unsuccessful, multi touch.
-        INCOMPLETE_LONG_PRESS = 7;  // Unsuccessful, long press.
-        INCOMPLETE_VERTICAL_MOVE = 8;  // Unsuccessful, move vertically.
-    }
-    optional BackType type = 1;
-
-    optional int32 y_coordinate = 2 [deprecated = true]; // y coordinate for ACTION_DOWN event
-    optional int32 start_x = 4;  // X coordinate for ACTION_DOWN event.
-    optional int32 start_y = 5;  // Y coordinate for ACTION_DOWN event.
-    optional int32 end_x = 6;   // X coordinate for ACTION_MOVE event.
-    optional int32 end_y = 7;  // Y coordinate for ACTION_MOVE event.
-    optional int32 left_boundary = 8;  // left edge width + left inset
-    optional int32 right_boundary = 9;  // screen width - (right edge width + right inset)
-    // The score between 0 and 1 which is the prediction output for the Back Gesture model.
-    optional float ml_model_score = 10;
-    optional string package_name = 11;  // The name of the top 100 most used package by all users.
-
-    enum WindowHorizontalLocation {
-        DEFAULT_LOCATION = 0;
-        LEFT = 1;
-        RIGHT = 2;
-    }
-    optional WindowHorizontalLocation x_location = 3 [deprecated = true];
-}
-
-message ExclusionRectStateChanged {
-    optional string component_name = 1;    // if not available, simply packageName
-    optional int32 requested_height = 2;   // px
-    optional int32 rejected_height = 3;    // px
-
-    enum WindowHorizontalLocation {
-        DEFAULT_LOCATION = 0;
-        LEFT = 1;
-        RIGHT = 2;
-    }
-    optional WindowHorizontalLocation x_location = 4;
-    optional bool landscape = 5;
-    optional bool splitscreen = 6;
-    optional int32 duration_millis = 7;
-}
-
-/**
- * Logs when IME is on.
- *
- * Logged from: /packages/SystemUI/src/com/android/systemui/
-                statusbar/phone/NavigationBarView.java
- *
- */
-message ImeTouchReported {
-    optional int32 x_coordinate = 1;  // X coordinate for ACTION_DOWN event.
-    optional int32 y_coordinate = 2;  // Y coordinate for ACTION_DOWN event.
-}
-
-/**
- * Logs when Launcher (HomeScreen) UI has changed or was interacted.
- *
- * Logged from:
- *   packages/apps/Launcher3
- */
-message LauncherUIChanged {
-    optional android.stats.launcher.LauncherAction action = 1 [deprecated = true];
-    optional android.stats.launcher.LauncherState src_state = 2;
-    optional android.stats.launcher.LauncherState dst_state = 3;
-    optional android.stats.launcher.LauncherExtension extension = 4 [(log_mode) = MODE_BYTES, deprecated = true];
-    optional bool is_swipe_up_enabled = 5 [deprecated = true];
-
-    // The event id (e.g., app launch, drag and drop, long press)
-    optional int32 event_id = 6;
-    // The event's source or target id (e.g., icon, task, button)
-    optional int32 target_id = 7;
-    // If the target needs to be tracked, use this id field
-    optional int32 instance_id = 8;
-    optional int32 uid = 9 [(is_uid) = true];
-    optional string package_name = 10;
-    optional string component_name = 11;
-
-    // (x, y) coordinate and the index information of the target on the container
-    optional int32 grid_x = 12 [default = -1];
-    optional int32 grid_y = 13 [default = -1];
-    optional int32 page_id = 14 [default = -2];
-
-    // e.g., folder icon's (x, y) location and index information on the workspace
-    optional int32 grid_x_parent = 15 [default = -1];
-    optional int32 grid_y_parent = 16 [default = -1];
-    optional int32 page_id_parent = 17 [default = -2];
-
-    // e.g., SEARCHBOX_ALLAPPS, FOLDER_WORKSPACE
-    optional int32 hierarchy = 18;
-
-    optional bool is_work_profile = 19;
-
-    // Used to store the predicted rank of the target
-    optional int32 rank = 20 [default = -1];
-
-    // e.g., folderLabelState can be captured in the following two fields
-    optional int32 from_state = 21;
-    optional int32 to_state = 22;
-
-    // e.g., autofilled or suggested texts that are not user entered
-    optional string edittext = 23;
-
-    // e.g., number of contents inside a container (e.g., icons inside a folder)
-    optional int32 cardinality = 24;
-}
-
-/**
- * Used for snapshot of the HomeScreen UI elements
- *
- * Logged from:
- *   packages/apps/Launcher3
- */
-message LauncherStaticLayout {
-    // The event id (e.g., snapshot, drag and drop)
-    optional int32 event_id = 1;
-    // The event's source or target id (e.g., icon, shortcut, widget)
-    optional int32 target_id = 2;
-    // If the target needs to be tracked, use this id field
-    optional int32 instance_id = 3;
-    optional int32 uid = 4 [(is_uid) = true];
-    optional string package_name = 5;
-    optional string component_name = 6;
-
-    // (x, y) coordinate and the index information of the target on the container
-    optional int32 grid_x = 7 [default = -1];
-    optional int32 grid_y = 8 [default = -1];
-    optional int32 page_id = 9 [default = -2];
-
-    // e.g., folder icon's (x, y) location and index information on the workspace
-    // e.g., when used with widgets target, use these values for (span_x, span_y)
-    optional int32 grid_x_parent = 10 [default = -1];
-    optional int32 grid_y_parent = 11 [default = -1];
-    optional int32 page_id_parent = 12 [default = -2];
-
-    // UNKNOWN = 0
-    // HOTSEAT = 1
-    // WORKSPACE = 2
-    // FOLDER_HOTSEAT = 3
-    // FOLDER_WORKSPACE = 4
-    optional int32 hierarchy = 13;
-
-    optional bool is_work_profile = 14;
-
-    // e.g., PIN, WIDGET TRAY, APPS TRAY, PREDICTION
-    optional int32 origin = 15;
-
-    // e.g., number of icons inside a folder
-    optional int32 cardinality = 16;
-
-    // e.g., (x, y) span of the widget inside homescreen grid system
-    optional int32 span_x = 17 [default = 1];
-    optional int32 span_y = 18 [default = 1];
-}
-
-/**
- * Logs when Wallpaper or ThemePicker UI has changed.
- *
- * Logged from:
- *   packages/apps/ThemePicker
- *   packages/apps/WallpaperPicker2
- */
-message StyleUIChanged {
-    optional android.stats.style.Action action = 1;
-    optional int32 color_package_hash = 2;
-    optional int32 font_package_hash  = 3;
-    optional int32 shape_package_hash = 4;
-    optional int32 clock_package_hash = 5;
-    optional int32 launcher_grid = 6;
-    optional int32 wallpaper_category_hash = 7;
-    optional int32 wallpaper_id_hash = 8;
-    optional int32 color_preference = 9;
-    optional android.stats.style.LocationPreference location_preference = 10;
-    optional android.stats.style.DatePreference date_preference = 11;
-    optional android.stats.style.LaunchedPreference launched_preference = 12;
-}
-
-/**
- * Logs when Settings UI has changed.
- *
- * Logged from:
- *   packages/apps/Settings
- */
-message SettingsUIChanged {
-    /**
-     * Where this SettingsUIChange event comes from. For example, if
-     * it's a PAGE_VISIBLE event, where the page is opened from.
-     */
-    optional android.app.settings.PageId attribution = 1;
-
-    /**
-     * What the UI action is.
-     */
-    optional android.app.settings.Action action = 2;
-
-    /**
-     * Where the action is happening
-     */
-    optional android.app.settings.PageId page_id = 3;
-
-    /**
-     * What preference changed in this event.
-     */
-    optional string changed_preference_key = 4;
-
-    /**
-     * The new value of the changed preference.
-     */
-    optional int64 changed_preference_int_value = 5;
-}
-
-/**
- * Logs basic timing information about touch events.
- * Reported at most every 5 minutes while device is being interacted with.
- *
- * Logged from:
- *   frameworks/native/services/inputflinger
- */
-message TouchEventReported {
-    /**
-     * The fields latency_{min|max|mean|stdev} represent minimum, maximum, mean,
-     * and the standard deviation of the time spent processing touchscreen events
-     * in the kernel and inputflinger. The units are microseconds.
-     *
-     * On supported devices, the starting point is taken during the hard interrupt inside the
-     * kernel touch driver. On all other devices, the starting point is taken inside
-     * the kernel's input event subsystem upon receipt of the input event.
-     * The ending point is taken inside InputDispatcher, just after the input event
-     * is sent to the app.
-     */
-    // Minimum value
-    optional float latency_min_micros = 1;
-    // Maximum value
-    optional float latency_max_micros = 2;
-    // Average value
-    optional float latency_mean_micros = 3;
-    // Standard deviation
-    optional float latency_stdev_micros = 4;
-    // Number of touch events (input_event) in this report
-    optional int32 count = 5;
-}
-
-/**
- * Logs gesture classification and timing information for touch events.
- *
- * Logged from:
- *   frameworks/base/core/java/android/view/GestureDetector.java
- *   frameworks/base/core/java/android/view/View.java
- */
-message TouchGestureClassified {
-    // The source of the classification (e.g. Java class name).
-    optional string source = 1;
-
-    enum Classification {
-        UNKNOWN_CLASSIFICATION = 0;
-        SINGLE_TAP = 1;
-        DOUBLE_TAP = 2;
-        LONG_PRESS = 3;
-        DEEP_PRESS = 4;
-        SCROLL = 5;
-    }
-    // The classification of the gesture.
-    optional Classification classification = 2;
-
-    // The interval from the start of a touch event stream until the
-    // classification was made.
-    optional int32 latency_millis = 3;
-
-    // The distance from the location of the first touch event to the
-    // location of the touch event when the classification was made.
-    optional float displacement_px = 4;
-}
-
-/**
- * Logs that a setting was updated.
- * Logged from:
- *   frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
- * The tag and is_default allow resetting of settings to default values based on the specified
- * tag. See Settings#putString(ContentResolver, String, String, String, boolean) for more details.
- */
-message SettingChanged {
-    // The name of the setting.
-    optional string setting = 1;
-
-    // The change being imposed on this setting. May represent a number, eg "3".
-    optional string value = 2;
-
-    // The new value of this setting. For most settings, this is same as value. For some settings,
-    // value is +X or -X where X represents an element in a set. For example, if the previous value
-    // is A,B,C and value is -B, then new_value is A,C and prev_value is A,B,C.
-    // The +/- feature is currently only used for location_providers_allowed.
-    optional string new_value = 3;
-
-    // The previous value of this setting.
-    optional string prev_value = 4;
-
-    // The tag used with the is_default for resetting sets of settings. This is generally null.
-    optional string tag = 5;
-
-    // True if this setting with tag should be resettable.
-    optional bool is_default = 6;
-
-    // The associated user (for multi-user feature). Defined in android/os/UserHandle.java
-    optional int32 user = 7;
-
-    enum ChangeReason {
-        UPDATED = 1; // Updated can be an insertion or an update.
-        DELETED = 2;
-    }
-    optional ChangeReason reason = 8;
-}
-
-/**
- * Logs activity going to foreground or background
- *
- * Logged from:
-  *   frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
- */
-message ActivityForegroundStateChanged {
-    optional int32 uid = 1 [(is_uid) = true];
-    optional string pkg_name = 2;
-    optional string class_name = 3;
-
-    enum State {
-        BACKGROUND = 0;
-        FOREGROUND = 1;
-    }
-    optional State state = 4;
-}
-
-/**
- * Logs when a volume entered low Storage state.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
- */
-message LowStorageStateChanged {
-    // Volume that ran out of storage.
-    optional string volume_description = 1;
-
-    enum State {
-        UNKNOWN = 0;
-        OFF = 1;
-        ON = 2;
-    }
-    optional State state = 2;
-}
-
-/**
- * Logs when an app is downgraded.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/pm/BackgroundDexOptService.java
- */
-message AppDowngraded {
-    optional string package_name = 1;
-    // Size of the package (all data) before being downgraded.
-    optional int64 size_in_bytes_before = 2;
-    // Size of the package (all data) after being downgraded.
-    optional int64 size_in_bytes_after = 3;
-
-    optional bool aggressive = 4;
-}
-
-/**
- * Logs when an app is optimized after being downgraded.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/pm/BackgroundDexOptService.java
- */
-message AppOptimizedAfterDowngraded {
-    optional string package_name = 1;
-}
-
-/**
- * Logs whenever an app is installed on external storage.
- * Logged from:
-        frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
- */
-message AppInstallOnExternalStorageReported {
-    // The type of external storage.
-    optional android.stats.storage.ExternalStorageType storage_type = 1;
-    // The name of the package that is installed on the sd card.
-    optional string package_name = 2;
-}
-
-/**
- * Logs when an app crashes.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message AppCrashOccurred {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional string event_type = 2;
-
-    // The name of the process.
-    // system_server if it is not by an app
-    optional string process_name = 3;
-
-    // The pid if available. -1 means not available.
-    optional int32 pid = 4;
-
-    optional string package_name = 5;
-
-    enum InstantApp {
-        UNAVAILABLE = 0;
-        FALSE = 1;
-        TRUE = 2;
-    }
-    optional InstantApp is_instant_app = 6;
-
-    enum ForegroundState {
-        UNKNOWN = 0;
-        BACKGROUND = 1;
-        FOREGROUND = 2;
-    }
-    optional ForegroundState foreground_state = 7;
-
-    optional android.server.ErrorSource error_source = 8;
-
-    optional bool is_package_loading = 9;
-}
-
-/**
- * Logs when a WTF (What a Terrible Failure) happened.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message WTFOccurred {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional string tag = 2;
-
-    // The name of the process.
-    // system_server if it is not by an app
-    optional string process_name = 3;
-
-    // The pid if available. -1 means not available.
-    optional int32 pid = 4;
-
-    optional android.server.ErrorSource error_source = 5;
-}
-
-/**
- * Logs when system server reports low memory.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message LowMemReported {
-}
-
-/**
- * Logs when an app ANR (App Not Responding) occurs.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/am/AppErrors.java
- */
-message ANROccurred {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional string process_name = 2;
-
-    optional string short_component_name = 3;
-
-    optional string reason = 4;
-
-    enum InstantApp {
-        UNAVAILABLE = 0;
-        FALSE = 1;
-        TRUE = 2;
-    }
-    optional InstantApp is_instant_app = 5;
-
-    enum ForegroundState {
-        UNKNOWN = 0;
-        BACKGROUND = 1;
-        FOREGROUND = 2;
-    }
-    optional ForegroundState foreground_state = 6;
-
-    optional android.server.ErrorSource error_source = 7;
-
-    optional string package_name = 8;
-
-    optional bool is_package_loading = 9;
-}
-
-/**
- * Logs when the vibrator state changes.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/VibratorService.java
- */
-message VibratorStateChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    enum State {
-        OFF = 0;
-        ON = 1;
-    }
-    optional State state = 2;
-
-    // Duration (in milliseconds) requested to keep the vibrator on.
-    // Only applicable for State == ON.
-    optional int64 duration_millis = 3;
-}
-
-/*
- * Allows other apps to push events into statsd.
- * Logged from:
- *      frameworks/base/core/java/android/util/StatsLog.java
- */
-message AppBreadcrumbReported {
-    // The uid of the application that sent this custom atom.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // An arbitrary label chosen by the developer. For Android P, the label should be in [0, 16).
-    optional int32 label = 2;
-
-    // Allows applications to easily use a custom event as start/stop boundaries (ie, define custom
-    // predicates for the metrics).
-    enum State {
-        UNKNOWN = 0;
-        UNSPECIFIED = 1;  // For events that are known to not represent START/STOP.
-        STOP = 2;
-        START = 3;
-    }
-    optional State state = 3;
-}
-
-/**
- * Logs the wall-clock time when a significant wall-clock time shift occurs.
- * For example, this could be due to the user manually changing the time.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
- */
-message WallClockTimeShifted {
-    // New wall-clock time in milliseconds, according to System.currentTimeMillis().
-    optional int64 wall_clock_timestamp_millis = 1;
-}
-
-/**
- * Logs when statsd detects an anomaly.
- *
- * Logged from:
- *   frameworks/base/cmds/statsd/src/anomaly/AnomalyTracker.cpp
- */
-message AnomalyDetected {
-    // Uid that owns the config whose anomaly detection alert fired.
-    optional int32 config_uid = 1 [(is_uid) = true];
-
-    // Id of the config whose anomaly detection alert fired.
-    optional int64 config_id = 2;
-
-    // Id of the alert (i.e. name of the anomaly that was detected).
-    optional int64 alert_id = 3;
-}
-
-message AppStartOccurred {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The app package name.
-    optional string pkg_name = 2;
-
-    enum TransitionType {
-        UNKNOWN = 0;
-        WARM = 1;
-        HOT = 2;
-        COLD = 3;
-        RELAUNCH = 4;
-    }
-    // The transition type.
-    optional TransitionType type = 3;
-
-    // The activity name.
-    optional string activity_name = 4;
-
-    // The name of the calling app. Empty if not set.
-    optional string calling_pkg_name = 5;
-
-    // Whether the app is an instant app.
-    optional bool is_instant_app = 6;
-
-    // Device uptime when activity started.
-    optional int64 activity_start_millis = 7;
-
-    optional android.app.AppTransitionReasonEnum reason = 8;
-
-    optional int32 transition_delay_millis = 9;
-    // -1 if not set.
-    optional int32 starting_window_delay_millis = 10;
-    // -1 if not set.
-    optional int32 bind_application_delay_millis = 11;
-    optional int32 windows_drawn_delay_millis = 12;
-
-    // Empty if not set.
-    optional string launch_token = 13;
-
-    // The compiler filter used when when the package was optimized.
-    optional int32 package_optimization_compilation_filter = 14;
-
-    // The reason why the package was optimized.
-    optional int32 package_optimization_compilation_reason = 15;
-
-    enum SourceType {
-        UNAVAILABLE = 0;
-        LAUNCHER = 1;
-        NOTIFICATION = 2;
-        LOCKSCREEN = 3;
-        RECENTS_ANIMATION = 4;
-    }
-    // The type of the startup source.
-    optional SourceType source_type = 16;
-
-    // The time from the startup source to the beginning of handling the startup event.
-    // -1 means not available.
-    optional int32 source_event_delay_millis = 17;
-}
-
-message AppStartCanceled {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The app package name.
-    optional string pkg_name = 2;
-
-    enum TransitionType {
-        UNKNOWN = 0;
-        WARM = 1;
-        HOT = 2;
-        COLD = 3;
-        RELAUNCH = 4;
-    }
-    // The transition type.
-    optional TransitionType type = 3;
-
-    // The activity name.
-    optional string activity_name = 4;
-}
-
-message AppStartFullyDrawn {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The app package name.
-    optional string pkg_name = 2;
-
-    enum TransitionType {
-        UNKNOWN = 0;
-        WITH_BUNDLE = 1;
-        WITHOUT_BUNDLE = 2;
-    }
-    // The transition type.
-    optional TransitionType type = 3;
-
-    // The activity name.
-    optional string activity_name = 4;
-
-    optional bool transition_process_running = 5;
-
-    // App startup time (until call to Activity#reportFullyDrawn()).
-    optional int64 app_startup_time_millis = 6;
-
-    // The compiler filter used when when the package was optimized.
-    optional int32 package_optimization_compilation_filter = 7;
-
-    // The reason why the package was optimized.
-    optional int32 package_optimization_compilation_reason = 8;
-
-    enum SourceType {
-        UNAVAILABLE = 0;
-        LAUNCHER = 1;
-        NOTIFICATION = 2;
-        LOCKSCREEN = 3;
-    }
-    // The type of the startup source.
-    optional SourceType source_type = 9;
-
-    // The time from the startup source to the beginning of handling the startup event.
-    // -1 means not available.
-    optional int32 source_event_delay_millis = 10;
-}
-
-/**
- * Logs a picture-in-picture action
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- *      frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
- *      frameworks/base/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
- */
-message PictureInPictureStateChanged {
-    // -1 if it is not available
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional string short_name = 2;
-
-    enum State {
-        ENTERED = 1;
-        EXPANDED_TO_FULL_SCREEN = 2;
-        MINIMIZED = 3;
-        DISMISSED = 4;
-    }
-    optional State state = 3;
-}
-
-/**
- * Logs overlay action
- * Logged from:
- *     services/core/java/com/android/server/wm/Session.java
- */
-message OverlayStateChanged {
-    optional int32 uid = 1 [(state_field_option).primary_field = true, (is_uid) = true];
-
-    optional string package_name = 2 [(state_field_option).primary_field = true];
-
-    optional bool using_alert_window = 3;
-
-    enum State {
-        ENTERED = 1;
-        EXITED = 2;
-    }
-    optional State state = 4
-            [(state_field_option).exclusive_state = true, (state_field_option).nested = false];
-}
-
-/**
- * Logs foreground service starts and stops.
- * Note that this is not when a service starts or stops, but when it is
- * considered foreground.
- * Logged from
- *     frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
- */
-message ForegroundServiceStateChanged {
-    optional int32 uid = 1 [(is_uid) = true];
-    // package_name + "/" + class_name
-    optional string short_name = 2;
-
-    enum State {
-        ENTER = 1;
-        EXIT = 2;
-    }
-    optional State state = 3;
-
-    // Whether the fgs is allowed while-in-use permissions, i.e. is considered 'in-use' to the user.
-    // (If the fgs was started while the app wasn't TOP it usually will be denied these permissions)
-    optional bool allow_while_in_use_permission = 4;
-}
-
-/**
- * Logs the number of times a uid accesses a sensitive AppOp during a foreground service session.
- * A foreground service session is any continuous period during which the uid holds at least one
- * foreground service; the atom will be pushed when the uid no longer holds any foreground services.
- * Accesses initiated while the uid is in the TOP state are ignored.
- * Sessions with no attempted accesses are not logged.
- * Logged from
- *     frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
- */
-message ForegroundServiceAppOpSessionEnded {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The operation's name.
-    // Only following four ops are logged
-    // COARSE_LOCATION = 0
-    // FINE_LOCATION = 1
-    // CAMERA = 26
-    // RECORD_AUDIO = 27
-    optional android.app.AppOpEnum app_op_name = 2 [default = APP_OP_NONE];
-
-    // The uid's permission mode for accessing the AppOp during this fgs session.
-    enum Mode {
-        MODE_UNKNOWN = 0;
-        MODE_ALLOWED = 1; // Always allowed
-        MODE_IGNORED = 2; // Denied
-        MODE_FOREGROUND = 3; // Allow-while-in-use (or allowed-one-time)
-    }
-    optional Mode app_op_mode = 3;
-
-    // Number of times this AppOp was requested and allowed.
-    optional int32 count_ops_accepted = 4;
-    // Number of times this AppOp was requested but denied.
-    optional int32 count_ops_rejected = 5;
-}
-
-/**
- * Logs creation or removal of an isolated uid. Isolated uid's are temporary uid's to sandbox risky
- * behavior in its own uid. However, the metrics of these isolated uid's almost always should be
- * attributed back to the parent (host) uid. One example is Chrome.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message IsolatedUidChanged {
-    // The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
-    // NOTE: DO NOT annotate uid field in this atom. This atom is specially handled in statsd.
-    // This field is ignored when event == REMOVED.
-    optional int32 parent_uid = 1;
-
-    optional int32 isolated_uid = 2;
-
-    // We expect an isolated uid to be removed before if it's used for another parent uid.
-    enum Event {
-        REMOVED = 0;
-        CREATED = 1;
-    }
-    optional Event event = 3;
-}
-
-/*
- * Logs the reception of an incoming network packet causing the main system to wake up for
- * processing that packet. These events are notified by the kernel via Netlink NFLOG to Netd
- * and processed by WakeupController.cpp.
- */
-message PacketWakeupOccurred {
-    // The uid owning the socket into which the packet was delivered, or -1 if the packet was
-    // delivered nowhere.
-    optional int32 uid = 1 [(is_uid) = true];
-    // The interface name on which the packet was received.
-    optional string iface = 2;
-    // The ethertype value of the packet.
-    optional int32 ethertype = 3;
-    // String representation of the destination MAC address of the packet.
-    optional string destination_hardware_address = 4;
-    // String representation of the source address of the packet if this was an IP packet.
-    optional string source_ip = 5;
-    // String representation of the destination address of the packet if this was an IP packet.
-    optional string destination_ip = 6;
-    // The value of the protocol field if this was an IPv4 packet or the value of the Next Header
-    // field if this was an IPv6 packet. The range of possible values is the same for both IP
-    // families.
-    optional int32 ip_next_header = 7;
-    // The source port if this was a TCP or UDP packet.
-    optional int32 source_port = 8;
-    // The destination port if this was a TCP or UDP packet.
-    optional int32 destination_port = 9;
-}
-
-/*
- * Logs the memory stats for an app on startup.
- * Logged from:
- *     frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message AppStartMemoryStateCaptured {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name.
-    optional string process_name = 2;
-
-    // The activity name.
-    optional string activity_name = 3;
-
-    // # of page-faults
-    optional int64 page_fault = 4;
-
-    // # of major page-faults
-    optional int64 page_major_fault = 5;
-
-    // RSS
-    optional int64 rss_in_bytes = 6;
-
-    // CACHE
-    optional int64 cache_in_bytes = 7;
-
-    // SWAP
-    optional int64 swap_in_bytes = 8;
-}
-
-/*
- * Logs the change in Low Memory Killer Daemon (LMKD) state which is used as start/stop boundaries
- * for LMK event.
- * Logged from:
- *      system/core/lmkd/lmkd.c
- */
-message LmkStateChanged {
-    enum State {
-        UNKNOWN = 0;
-        START = 1;
-        STOP = 2;
-    }
-    optional State state = 1;
-}
-
-/*
- * Logs the event when Low Memory Killer Daemon (LMKD) kills a process to reduce memory pressure.
- * Logged from:
- *      system/core/lmkd/lmkd.c
- */
-message LmkKillOccurred {
-    enum Reason {
-        UNKNOWN = 0;
-        PRESSURE_AFTER_KILL = 1;
-        NOT_RESPONDING = 2;
-        LOW_SWAP_AND_THRASHING = 3;
-        LOW_MEM_AND_SWAP = 4;
-        LOW_MEM_AND_THRASHING = 5;
-        DIRECT_RECL_AND_THRASHING = 6;
-        LOW_MEM_AND_SWAP_UTIL = 7;
-    }
-
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name.
-    optional string process_name = 2;
-
-    // oom adj score.
-    optional int32 oom_adj_score = 3;
-
-    // # of page-faults
-    optional int64 page_fault = 4;
-
-    // # of major page-faults
-    optional int64 page_major_fault = 5;
-
-    // RSS
-    optional int64 rss_in_bytes = 6;
-
-    // CACHE
-    optional int64 cache_in_bytes = 7;
-
-    // SWAP
-    optional int64 swap_in_bytes = 8;
-
-    // The elapsed real time of start of the process.
-    optional int64 process_start_time_nanos = 9;
-
-    // Min oom adj score considered by lmkd.
-    optional int32 min_oom_score = 10;
-
-    // Free physical memory on device at LMK time.
-    optional int32 free_mem_kb = 11;
-
-    // Free swap on device at LMK time.
-    optional int32 free_swap_kb = 12;
-
-    // What triggered the LMK event.
-    optional Reason reason = 13;
-}
-
-/*
- * Logs when the ActivityManagerService detects that an app died.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message AppDied {
-    // timestamp(elapsedRealtime) of record creation
-    optional uint64 timestamp_millis = 1 [(state_field_option).exclusive_state = true];
-}
-
-/**
- * An atom for generic metrics logging. Available from Android Q.
- */
-message GenericAtom {
-    // The uid of the application that sent this custom atom.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // An event_id indicates the type of event.
-    optional android.stats.EventType event_id = 2;
-}
-
-/**
- * Atom for simple logging of user interaction and impression events, such as "the user touched
- * this button" or "this dialog was displayed".
- * Keep the UI event stream clean: don't use for system or background events.
- * Log using the UiEventLogger wrapper - don't write with the StatsLog API directly.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/
- *   frameworks/base/packages/SystemUI/src/com/android/systemui/
- */
-message UiEventReported {
-    // The event_id.
-    optional int32 event_id = 1;
-    // The event's source or target uid and package, if applicable.
-    // For example, the package posting a notification, or the destination package of a share.
-    optional int32 uid = 2 [(is_uid) = true];
-    optional string package_name = 3;
-    // An identifier used to disambiguate which logs refer to a particular instance of some
-    // UI element. Useful when there might be multiple instances simultaneously active.
-    optional int32 instance_id = 4;
-}
-
-/**
- * Reports a notification was created or updated.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/notification/
- */
-message NotificationReported {
-    // The event_id (as for UiEventReported).
-    optional int32 event_id = 1;
-    // The notifying app's uid and package.
-    optional int32 uid = 2 [(is_uid) = true];
-    optional string package_name = 3;
-    // A small system-assigned identifier for the notification.
-    // Locally probably-unique, but expect collisions across users and/or days.
-    optional int32 instance_id = 4;
-    optional int32 notification_id_hash = 5;  // Small hash of the app-assigned notif ID + tag
-    optional int32 channel_id_hash = 6;  // Small hash of app-assigned channel ID
-
-    // Grouping information
-    optional int32 group_id_hash = 7;  // Small hash of the group ID of the notification
-    optional int32 group_instance_id = 8;  // Instance_id of the group-summary notification
-    optional bool is_group_summary = 9;  // Tags the group-summary notification
-
-    // Attributes
-    optional string category = 10;   // App-assigned notification category (API-defined strings)
-    optional int32 style = 11;       // App-assigned notification style
-    optional int32 num_people = 12;  // Number of Person records attached to the notification
-
-    // Ordering, importance and interruptiveness
-
-    optional int32 position = 13;    // Position in NotificationManager's list
-
-    optional android.stats.sysui.NotificationImportance importance = 14;
-    optional int32 alerting = 15;    // Bitfield, 1=buzz 2=beep 4=blink
-
-    enum NotificationImportanceExplanation {
-        IMPORTANCE_EXPLANATION_UNKNOWN = 0;
-        IMPORTANCE_EXPLANATION_APP = 1;     // App-specified channel importance.
-        IMPORTANCE_EXPLANATION_USER = 2;    // User-specified channel importance.
-        IMPORTANCE_EXPLANATION_ASST = 3;    // Notification Assistant override.
-        IMPORTANCE_EXPLANATION_SYSTEM = 4;  // System override.
-        // Like _APP, but based on pre-channels priority signal.
-        IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS = 5;
-    }
-
-    optional NotificationImportanceExplanation importance_source = 16;
-    optional android.stats.sysui.NotificationImportance importance_initial = 17;
-    optional NotificationImportanceExplanation importance_initial_source = 18;
-    optional android.stats.sysui.NotificationImportance importance_asst = 19;
-    optional int32 assistant_hash = 20;
-    optional float assistant_ranking_score = 21;
-}
-
-message Notification {
-    // The notifying app's uid and package.
-    optional int32 uid = 1 [(is_uid) = true];
-    optional string package_name = 2;
-    // A small system-assigned identifier for the notification.
-    optional int32 instance_id = 3;
-
-    // Grouping information.
-    optional int32 group_instance_id = 4;
-    optional bool is_group_summary = 5;
-
-    // The section of the shade that the notification is in.
-    // See SystemUI Notifications.proto.
-    enum NotificationSection {
-        SECTION_UNKNOWN = 0;
-        SECTION_HEADS_UP = 1;
-        SECTION_MEDIA_CONTROLS = 2;
-        SECTION_PEOPLE = 3;
-        SECTION_ALERTING = 4;
-        SECTION_SILENT = 5;
-        SECTION_FOREGROUND_SERVICE = 6;
-    }
-    optional NotificationSection section = 6;
-}
-
-message NotificationList {
-    repeated Notification notifications = 1;  // An ordered sequence of notifications.
-}
-
-/**
- * Reports a notification panel was displayed, e.g. from the lockscreen or status bar.
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/
- */
-message NotificationPanelReported {
-    // The event_id (as for UiEventReported).
-    optional int32 event_id = 1;
-    optional int32 num_notifications = 2;
-    // The notifications in the panel, in the order that they appear there.
-    optional NotificationList notifications = 3 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Reports a notification channel, or channel group, was created, updated, or deleted.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/notification/
- */
-message NotificationChannelModified {
-    // The event_id (as for UiEventReported).
-    optional int32 event_id = 1;
-    // The notifying app's uid and package.
-    optional int32 uid = 2 [(is_uid) = true];
-    optional string package_name = 3;
-    // Hash of app-assigned notification channel ID or channel-group ID
-    optional int32 channel_id_hash = 4;
-    // Previous importance setting, if applicable
-    optional android.stats.sysui.NotificationImportance old_importance = 5;
-    // New importance setting
-    optional android.stats.sysui.NotificationImportance importance = 6;
-    // whether or not this channel represents a conversation
-    optional bool is_conversation = 7;
-    // Hash of app-assigned notification conversation id
-    optional int32 conversation_id_hash = 8;
-    // whether or not the user demoted this channel out of the conversation space
-    optional bool is_conversation_demoted = 9;
-    // whether this conversation is marked as being a priority
-    optional bool is_conversation_priority = 10;
-}
-
-/**
- * Logs when a biometric acquire event occurs.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/biometrics
- */
-message BiometricAcquired {
-    // Biometric modality that was acquired.
-    optional android.hardware.biometrics.ModalityEnum modality = 1;
-    // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java.
-    optional int32 user = 2;
-    // If this acquire is for a crypto operation. e.g. Secure purchases, unlock password storage.
-    optional bool is_crypto = 3;
-    // Action that the device is performing. Acquired messages are only expected for enroll and
-    // authenticate. Other actions may indicate an error.
-    optional android.hardware.biometrics.ActionEnum action = 4;
-    // The client that this acquisition was received for.
-    optional android.hardware.biometrics.ClientEnum client = 5;
-    // Acquired constants, e.g. ACQUIRED_GOOD. See constants defined by <Biometric>Manager.
-    optional int32 acquire_info = 6;
-    // Vendor-specific acquire info. Valid only if acquire_info == ACQUIRED_VENDOR.
-    optional int32 acquire_info_vendor = 7;
-    // Dictates if this message should trigger additional debugging.
-    optional bool debug = 8;
-}
-
-/**
- * Logs when a biometric authentication event occurs.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/biometrics
- */
-message BiometricAuthenticated {
-    // Biometric modality that was used.
-    optional android.hardware.biometrics.ModalityEnum modality = 1;
-    // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java
-    optional int32 user = 2;
-    // If this authentication is for a crypto operation. e.g. Secure purchases, unlock password
-    // storage.
-    optional bool is_crypto = 3;
-    // The client that this acquisition was received for.
-    optional android.hardware.biometrics.ClientEnum client = 4;
-    // If authentication requires user confirmation. See BiometricPrompt's
-    // setRequireConfirmation(bool) method.
-    optional bool require_confirmation = 5;
-
-    enum State {
-        UNKNOWN = 0;
-        REJECTED = 1;
-        PENDING_CONFIRMATION = 2;
-        CONFIRMED = 3;
-    }
-
-    // State of the current auth attempt.
-    optional State state = 6;
-    // Time it took to authenticate. For BiometricPrompt where setRequireConfirmation(false) is
-    // specified and supported by the biometric modality, this is from the first ACQUIRED_GOOD to
-    // AUTHENTICATED. for setRequireConfirmation(true), this is from PENDING_CONFIRMATION to
-    // CONFIRMED.
-    optional int64 latency_millis = 7;
-    // Dictates if this message should trigger additional debugging.
-    optional bool debug = 8;
-}
-
-/**
- * Logs when a biometric error occurs.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/biometrics
- */
-message BiometricErrorOccurred {
-    // Biometric modality that was used.
-    optional android.hardware.biometrics.ModalityEnum modality = 1;
-    // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java
-    optional int32 user = 2;
-    // If this error is for a crypto operation. e.g. Secure purchases, unlock password storage.
-    optional bool is_crypto = 3;
-    // Action that the device is performing.
-    optional android.hardware.biometrics.ActionEnum action = 4;
-    // The client that this acquisition was received for.
-    optional android.hardware.biometrics.ClientEnum client = 5;
-    // Error constants. See constants defined by <Biometric>Manager. Enums won't work since errors
-    // are unique to modality.
-    optional int32 error_info = 6;
-    // Vendor-specific error info. Valid only if acquire_info == ACQUIRED_VENDOR. These are defined
-    // by the vendor and not specified by the HIDL interface.
-    optional int32 error_info_vendor = 7;
-    // Dictates if this message should trigger additional debugging.
-    optional bool debug = 8;
-    // Time spent during the authentication attempt.
-    optional int64 latency_millis = 9;
-}
-
-/**
- * Logs when a system health issue is detected.
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/biometrics
- */
-message BiometricSystemHealthIssueDetected {
-    // Biometric modality.
-    optional android.hardware.biometrics.ModalityEnum modality = 1;
-    // Type of issue detected.
-    optional android.hardware.biometrics.IssueEnum issue = 2;
-    // Dictates if this message should trigger additional debugging.
-    optional bool debug = 3;
-}
-
-/**
- * Logs when a biometric enrollment occurs.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/biometrics
- */
-message BiometricEnrolled {
-    // Biometric modality that was used.
-    optional android.hardware.biometrics.ModalityEnum modality = 1;
-    // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java
-    optional int32 user = 2;
-    // The amount of time the enrollment took in milliseconds.
-    optional int64 latency_millis = 3;
-    // Whether or not the enrollment was successful.
-    optional bool success = 4;
-}
-
-/*
- * Logs when a flag flip update occurrs. Used for mainline modules that update via flag flips.
- */
-message FlagFlipUpdateOccurred {
-    // If the event is from a flag config package, specify the package name.
-    optional string flag_flip_package_name = 1;
-
-    // The order id of the package
-    optional int64 order_id = 2;
-}
-
-/**
- * Potential experiment ids that goes with a train install.
- * Should be kept in sync with experiment_ids.proto.
- */
-message TrainExperimentIds {
-    repeated int64 experiment_id = 1;
-}
-
-/*
- * Logs when a binary push state changes.
- * Logged by the installer via public api.
- */
-message BinaryPushStateChanged {
-    // Name of the train.
-    optional string train_name = 1;
-    // Version code for a "train" of packages that need to be installed atomically
-    optional int64 train_version_code = 2;
-    // After installation of this package, device requires a restart.
-    optional bool requires_staging = 3;
-    // Rollback should be enabled for this install.
-    optional bool rollback_enabled = 4;
-    // Requires low latency monitoring if possible.
-    optional bool requires_low_latency_monitor = 5;
-
-    enum State {
-        UNKNOWN = 0;
-        INSTALL_REQUESTED = 1;
-        INSTALL_STARTED = 2;
-        INSTALL_STAGED_NOT_READY = 3;
-        INSTALL_STAGED_READY = 4;
-        INSTALL_SUCCESS = 5;
-        // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH,
-        // and INSTALL_FAILURE_COMMIT.
-        INSTALL_FAILURE = 6  [deprecated = true];
-        // This enum is for installs that are manually cancelled via the Manual Update UI.
-        INSTALL_CANCELLED = 7;
-        INSTALLER_ROLLBACK_REQUESTED = 8;
-        INSTALLER_ROLLBACK_INITIATED = 9;
-        INSTALLER_ROLLBACK_INITIATED_FAILURE = 10;
-        INSTALLER_ROLLBACK_STAGED = 11;
-        INSTALLER_ROLLBACK_STAGED_FAILURE = 12;
-        INSTALLER_ROLLBACK_BOOT_TRIGGERED = 13;
-        INSTALLER_ROLLBACK_BOOT_TRIGGERED_FAILURE = 14;
-        INSTALLER_ROLLBACK_SUCCESS = 15;
-        INSTALLER_ROLLBACK_FAILURE = 16;
-        INSTALLER_ROLLBACK_STAGED_CANCEL_REQUESTED = 17;
-        INSTALLER_ROLLBACK_STAGED_CANCEL_SUCCESS = 18;
-        INSTALLER_ROLLBACK_STAGED_CANCEL_FAILURE = 19;
-        INSTALL_STAGED_CANCEL_REQUESTED = 20;
-        INSTALL_STAGED_CANCEL_SUCCESS = 21;
-        INSTALL_STAGED_CANCEL_FAILURE = 22;
-        INSTALL_FAILURE_DOWNLOAD = 23;
-        INSTALL_FAILURE_STATE_MISMATCH = 24;
-        INSTALL_FAILURE_COMMIT = 25;
-        REBOOT_TRIGGERED = 26;
-        // Logged after INSTALL_REQUESTED for devices installing a train that
-        // contains no module requiring reboot.
-        REBOOT_NOT_REQUIRED = 27;
-        // Logged after INSTALL_REQUESTED for devices that are installing a train
-        // which requires reboot and eligible for soft restart.
-        SOFT_RESTART_ELIGIBLE = 28;
-        // Logged after INSTALL_REQUESTED for devices that are installing a train
-        // which requires reboot and eligible for notification restart.
-        NOTIFICATION_RESTART_ELIGIBLE = 29;
-        // Logged after INSTALL_REQUESTED for devices that are installing a train
-        // which requires reboot and not eligible for any reboot promotion strategy
-        // (e.g. soft restart, notification restart).
-        NO_REBOOT_PROMOTION_STRATEGY_ELIGIBLE = 30;
-        REBOOT_TRIGGER_FAILURE = 31;
-    }
-    optional State state = 6;
-    // Possible experiment ids for monitoring this push.
-    optional TrainExperimentIds experiment_ids = 7 [(log_mode) = MODE_BYTES];
-    // user id
-    optional int32 user_id = 8;
-    optional int32 reason = 9;
-    // Whether or not this is a rollback event
-    optional bool is_rollback = 10;
-}
-
-/* Test atom, is not logged anywhere */
-message TestAtomReported {
-    repeated AttributionNode attribution_node = 1;
-    optional int32 int_field = 2;
-    optional int64 long_field = 3;
-    optional float float_field = 4;
-    optional string string_field = 5;
-    optional bool boolean_field = 6;
-    enum State {
-        UNKNOWN = 0;
-        OFF = 1;
-        ON = 2;
-    }
-    optional State state = 7;
-    optional TrainExperimentIds bytes_field = 8 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/** Represents USB port overheat event. */
-message UsbPortOverheatEvent {
-    /* Temperature of USB port at USB plug event, in 1/10ths of degree C. */
-    optional int32 plug_temperature_deci_c = 1;
-
-    /* Maximum temperature of USB port during overheat event, in 1/10ths of degree C. */
-    optional int32 max_temperature_deci_c = 2;
-
-    /* Time between USB plug event and overheat threshold trip, in seconds. */
-    optional int32 time_to_overheat_secs = 3;
-
-    /* Time between overheat threshold trip and hysteresis, in seconds. */
-    optional int32 time_to_hysteresis_secs = 4;
-
-    /* Time between hysteresis and active mitigation ending, in seconds. */
-    optional int32 time_to_inactive_secs = 5;
-};
-
-/**
- * Logs total effective full charge and discharge cycles on a battery.
- * Here are some examples of one effective cycle:
- *   1) the battery charges from 0% to 100% and drains back to 0%,
- *   2) charging from 50% to 100% and draining back to 50% twice.
- * Pulled from:
- *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
- */
-message BatteryCycleCount {
-    /* Number of total charge and discharge cycles on the system battery. */
-    optional int32 cycle_count = 1;
-}
-
-/**
- * Logs that external storage is mounted and information about it, the storage type (sd card/usb/
- * others), its type (public or private) and the size in bytes.
- * Pulled from:
- *   StatsCompanionService
- */
-
-message ExternalStorageInfo {
-
-    enum VolumeType {
-        UNKNOWN = 0;
-        PUBLIC = 1;
-        PRIVATE = 2;
-        OTHER = 3;
-    }
-
-    // The type of external storage.
-    optional android.stats.storage.ExternalStorageType storage_type = 1;
-    // Type of the volume: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
-    optional VolumeType volume_type = 2;
-    // Total size of the sd card in bytes.
-    optional int64 size_bytes = 3;
-}
-
-/*
- * Logs when a connection becomes available and lost.
- * Logged in StatsCompanionService.java
- */
-message ConnectivityStateChanged {
-  // Id of the network.
-  optional int32 net_id = 1;
-
-  enum State {
-    UNKNOWN = 0;
-    CONNECTED = 1;
-    DISCONNECTED = 2;
-  }
-  // Connected state of a network.
-  optional State state = 2;
-}
-
-/**
- * Logs when a service starts and stops.
- * Logged from:
- *   services/core/java/com/android/server/am/ActiveServices.java
- */
-message ServiceStateChanged {
-
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional string package_name = 2;
-
-    optional string service_name = 3;
-
-    enum State {
-        START = 1;
-        STOP = 2;
-    }
-
-    optional State state = 4;
-}
-
-/**
- * Logs when a service is launched.
- * Logged from:
- *   services/core/java/com/android/server/am/ActiveServices.java
- */
-message ServiceLaunchReported {
-
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional string package_name = 2;
-
-    optional string service_name = 3;
-}
-
-/**
- * Logs when a hidden API is used.
- *
- * Logged from:
- *     libcore/libart/src/main/java/dalvik/system/VMRuntime.java
- */
-message HiddenApiUsed {
-    // The uid of the app making the hidden access.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Signature of the method or field accessed.
-    optional string signature = 2;
-
-    enum AccessMethod {
-        NONE = 0;
-        REFLECTION = 1;
-        JNI = 2;
-        LINKING = 3;
-    }
-
-    // Type of access.
-    optional AccessMethod access_method = 3;
-
-    // Whether the access was prevented or not.
-    optional bool access_denied = 4;
-}
-
-/**
- * Logs user interaction with the Privacy Indicators added in Q. In particular:
- * - When user sees privacy chip
- * - When user clicks privacy chip
- * - How does the user exit the Privacy Dialog
- * Logged from:
- *   packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
- */
-message PrivacyIndicatorsInteracted {
-
-    enum Type {
-        UNKNOWN = 0;
-        CHIP_VIEWED = 1;
-        CHIP_CLICKED = 2;
-        reserved 3; // Used only in beta builds, never shipped
-        DIALOG_DISMISS = 4;
-        DIALOG_LINE_ITEM = 5;
-    }
-
-    optional Type type = 1 [(state_field_option).exclusive_state = true];
-}
-
-/**
- * Logs information about a package that is moved from the internal to external storage and vice
- * versa.
- * It logs the package name, the type of the external storage where the package is installed
- * (if moved to external storage, or UNKNOWN if moved to internal storage),
- * and the move type: if it's from internal to external or the other way around.
- *
- * Logged from:
-        frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
- */
-message AppMovedStorageReported {
-    enum MoveType {
-        UNKNOWN = 0;
-        TO_EXTERNAL = 1;
-        TO_INTERNAL = 2;
-    }
-    // The type of the external storage.
-    optional android.stats.storage.ExternalStorageType external_storage_type = 1;
-    // The type of move.
-    optional MoveType move_type = 2;
-    // The name of the package that was moved.
-    optional string package_name = 3;
-}
-
-/**
- * Logs when system server watchdog occurs.
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/Watchdog.java
- */
-message SystemServerWatchdogOccurred {
-    optional string subject = 1;
-}
-
-/**
- * Logs when new file added to tombstones.
- * Logged from:
- *      frameworks/base/core/java/com/android/server/BootReceiver.java
- */
-message TombStoneOccurred {
-}
-
-/*
- * Information about a role request
- *
- * Logged from:
- *   packages/apps/PermissionController/src/com/android/packageinstaller/role/ui/RequestRoleFragment.java
- */
-message RoleRequestResultReported {
-    // UID of application requesting the role
-    optional int32 requesting_uid = 1;
-
-    // Package name of application requesting the role
-    optional string requesting_package_name = 2;
-
-    // The role to be granted
-    optional string role_name = 3;
-
-    // The count of applications qualifying for the role
-    optional int32 qualifying_count = 4;
-
-    // UID of application current granted the role
-    optional int32 current_uid = 5;
-
-    // Package name of application current granted the role
-    optional string current_package_name = 6;
-
-    // UID of another application that user chose to grant the role to, instead of the requesting
-    // application
-    optional int32 granted_another_uid = 7;
-
-    // Package name of another application that user chose to grant the role to, instead of the
-    // requesting application
-    optional string granted_another_package_name = 8;
-
-    enum Result {
-        UNDEFINED = 0;
-        // role request was ignored
-        IGNORED = 1;
-        // role request was ignored because it's already granted
-        IGNORED_ALREADY_GRANTED = 2;
-        // role request was ignored because the application isn't qualified
-        IGNORED_NOT_QUALIFIED = 3;
-        // role request was ignored because user said it should be always denied
-        IGNORED_USER_ALWAYS_DENIED = 4;
-        // role was granted by user action
-        USER_GRANTED = 5;
-        // role was denied by user action
-        USER_DENIED = 6;
-        // role was denied by user granting another application the role
-        USER_DENIED_GRANTED_ANOTHER = 7;
-        // role was denied and set to be always denied by the user
-        USER_DENIED_WITH_ALWAYS = 8;
-    }
-    // The result of the role request
-    optional Result result = 9;
-}
-
-/**
- * Logs when a Vehicle Maps Service client's connection state has changed
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/stats/VmsClientLog.java
- */
-message VmsClientConnectionStateChanged {
-    // The UID of the VMS client app
-    optional int32 uid = 1 [(is_uid) = true];
-
-    enum State {
-        UNKNOWN = 0;
-        // Attempting to connect to the client
-        CONNECTING = 1;
-        // Client connection established
-        CONNECTED = 2;
-        // Client connection closed unexpectedly
-        DISCONNECTED = 3;
-        // Client connection closed by VMS
-        TERMINATED = 4;
-        // Error establishing the client connection
-        CONNECTION_ERROR = 5;
-    }
-
-    optional State state  = 2;
-}
-
-message MimeTypes {
-    repeated string mime_types = 1;
-}
-
-/**
- * Logs statistics regarding accesses to external storage.
- * All stats are normalized for one day period.
- *
- * Logged from:
- *   packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
- */
-message GeneralExternalStorageAccessStats {
-    optional int32 uid = 1 [(is_uid) = true];
-    // Total number of accesses like creation, open, delete and rename/update.
-    // Includes file path and ContentResolver accesses
-    optional uint32 total_accesses = 2;
-    // Number of file path accesses, as opposed to file path and ContentResolver.
-    optional uint32 file_path_accesses = 3;
-    // Number of accesses on secondary volumes like SD cards.
-    // Includes file path and ContentResolver accesses
-    optional uint32 secondary_storage_accesses = 4;
-    // Comma-separated list of mime types that were accessed.
-    optional MimeTypes mime_types_accessed = 5 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs when MediaProvider has successfully finished scanning a storage volume.
- *
- * Logged from:
- *   packages/providers/MediaProvider/src/com/android/providers/media/scan/ModernMediaScanner.java
- */
-message MediaProviderScanOccurred {
-    enum Reason {
-        // Scan triggered due to unknown reason
-        UNKNOWN = 0;
-        // Scan triggered due to storage volume being mounted
-        MOUNTED = 1;
-        // Scan triggered due to explicit user action or app request
-        DEMAND = 2;
-        // Scan triggered due to idle maintenance
-        IDLE = 3;
-    }
-
-    // Volume type that this event pertains to
-    optional android.stats.mediaprovider.VolumeType volume_type = 1;
-    // Reason why this scan was triggered
-    optional Reason reason = 2;
-    // Total number of files scanned
-    optional int64 item_count = 3;
-    // Duration of scan, normalized per file
-    optional float normalized_duration_millis = 4;
-    // Number of database inserts, normalized per file
-    optional float normalized_insert_count = 5;
-    // Number of database updates, normalized per file
-    optional float normalized_update_count = 6;
-    // Number of database deletes, normalized per file
-    optional float normalized_delete_count = 7;
-}
-
-/**
- * Logs when an app has asked MediaProvider to delete media belonging to the user.
- *
- * Logged from:
- *   packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
- */
-message MediaContentDeleted {
-    // Volume type that this event pertains to
-    optional android.stats.mediaprovider.VolumeType volume_type = 1;
-    // UID of app that requested deletion
-    optional int32 uid = 2 [(is_uid) = true];
-    // Number of items that were deleted
-    optional int32 item_count = 3;
-}
-
-/**
- * Logs when an app has asked MediaProvider to grant them access to media belonging to the user.
- *
- * Logged from:
- *   packages/providers/MediaProvider/src/com/android/providers/media/PermissionActivity.java
- */
-message MediaProviderPermissionRequested {
-    enum Result {
-        UNKNOWN = 0;
-        USER_GRANTED = 1;
-        AUTO_GRANTED = 2;
-        USER_DENIED = 3;
-        USER_DENIED_WITH_PREJUDICE = 4;
-        AUTO_DENIED = 5;
-    }
-
-    // Volume type that this event pertains to
-    optional android.stats.mediaprovider.VolumeType volume_type = 1;
-    // UID of app that requested permission
-    optional int32 uid = 2 [(is_uid) = true];
-    // Number of items that were requested
-    optional int32 item_count = 3;
-    // Result of this request
-    optional Result result = 4;
-}
-
-/**
- * Logs when MediaProvider has finished upgrading or downgrading its database schema.
- *
- * Logged from:
- *   packages/providers/MediaProvider/src/com/android/providers/media/DatabaseHelper.java
- */
-message MediaProviderSchemaChanged {
-    // Volume type that this event pertains to
-    optional android.stats.mediaprovider.VolumeType volume_type = 1;
-    // Old database version code
-    optional int32 version_from = 2;
-    // New database version code
-    optional int32 version_to = 3;
-    // Total number of files in database
-    optional int64 item_count = 4;
-    // Duration of schema change, normalized per file
-    optional float normalized_duration_millis = 5;
-}
-
-/**
- * Logs when MediaProvider has finished an idle maintenance job.
- *
- * Logged from:
- *   packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
- */
-message MediaProviderIdleMaintenanceFinished {
-    // Volume type that this event pertains to
-    optional android.stats.mediaprovider.VolumeType volume_type = 1;
-
-    // Total number of files in database
-    optional int64 item_count = 2;
-    // Duration of idle maintenance, normalized per file
-    optional float normalized_duration_millis = 3;
-    // Number of thumbnails found to be stale, normalized per file
-    optional float normalized_stale_thumbnails = 4;
-    // Number of items found to be expired, normalized per file
-    optional float normalized_expired_media = 5;
-}
-
-/**
- * Represents boot time event with duration in ms.
- *
- * Logged from: bootstat and various system server components. Check each enums for details.
- */
-message BootTimeEventDuration {
-    enum DurationEvent {
-        UNKNOWN = 0;
-        // Bootloader time excluding BOOTLOADER_UI_WAIT + boot complete time. Logged from bootstat.
-        ABSOLUTE_BOOT_TIME = 1;
-        // Bootloader's 1st stage execution time.
-        // Logged from bootstat.
-        BOOTLOADER_FIRST_STAGE_EXEC = 2;
-        // Bootloader's 1st stage loading time.
-        // Logged from bootstat.
-        BOOTLOADER_FIRST_STAGE_LOAD = 3;
-        // Bootloader's kernel loading time.
-        // Logged from bootstat.
-        BOOTLOADER_KERNEL_LOAD = 4;
-        // Bootloader's 2nd stage execution time.
-        // Logged from bootstat.
-        BOOTLOADER_SECOND_STAGE_EXEC = 5;
-        // Bootloader's 2nd stage loading time.
-        // Logged from bootstat.
-        BOOTLOADER_SECOND_STAGE_LOAD = 6;
-        // Duration for Bootloader to show unlocked device's warning UI. This should not happen
-        // for locked device.
-        // Logged from bootstat.
-        BOOTLOADER_UI_WAIT = 7;
-        // Total time spend in bootloader. This is the sum of all BOOTLOADER_* listed above.
-        // Logged from bootstat.
-        BOOTLOADER_TOTAL = 8;
-        // Shutdown duration inside init for the reboot before the current boot up.
-        // Logged from f/b/services/.../BootReceiver.java.
-        SHUTDOWN_DURATION = 9;
-        // Total time for mounting of disk devices during bootup.
-        // Logged from f/b/services/.../BootReceiver.java.
-        MOUNT_DEFAULT_DURATION = 10;
-        // Total time for early stage mounting of disk devices during bootup.
-        // Logged from f/b/services/.../BootReceiver.java.
-        MOUNT_EARLY_DURATION = 11;
-        // Total time for late stage mounting of disk devices during bootup.
-        // Logged from f/b/services/.../BootReceiver.java.
-        MOUNT_LATE_DURATION = 12;
-        // Average time to scan non-system app after OTA
-        // Logged from f/b/services/.../PackageManagerService.java
-        OTA_PACKAGE_MANAGER_INIT_TIME = 13;
-        // Time to initialize Package manager after OTA
-        // Logged from f/b/services/.../PackageManagerService.java
-        OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME = 14;
-        // Time to scan all system app from Package manager after OTA
-        // Logged from f/b/services/.../PackageManagerService.java
-        OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME = 15;
-        // Init's total time for cold boot stage.
-        // Logged from bootstat.
-        COLDBOOT_WAIT = 16;
-        // Init's total time for initializing selinux.
-        // Logged from bootstat.
-        SELINUX_INIT = 17;
-        // Time since last factory reset.
-        // Logged from bootstat.
-        FACTORY_RESET_TIME_SINCE_RESET = 18;
-        // Init's total time spent for completing the 1st stage.
-        // Logged from bootstat.
-        ANDROID_INIT_STAGE_1 = 19;
-    }
-
-    // Type of the event.
-    optional DurationEvent event = 1;
-    // Duration of the event in ms.
-    optional int64 duration_millis = 2;
-}
-
-/**
- * Represents the start of specific boot time event during bootup in ms. This is usually a time
- * since boot-up.
- *
- * Logged from: bootstat and various system server components. Check each enums for details.
- */
-message BootTimeEventElapsedTime {
-    enum ElapsedTimeEvent {
-        UNKNOWN = 0;
-        // Time when init starts 1st stage. Logged from bootstat.
-        ANDROID_INIT_STAGE_1 = 1;
-        // Time when sys.boot_completed prop is set.
-        // Logged from bootstat.
-        BOOT_COMPLETE = 2;
-        // BOOT_COMPLETE for encrypted device.
-        BOOT_COMPLETE_ENCRYPTION = 3;
-        // BOOT_COMPLETE for device with no encryption.
-        BOOT_COMPLETE_NO_ENCRYPTION = 4;
-        // Adjusted BOOT_COMPLETE for encrypted device extracting decryption time.
-        BOOT_COMPLETE_POST_DECRYPT = 5;
-        // BOOT_COMPLETE after factory reset.
-        FACTORY_RESET_BOOT_COMPLETE = 6;
-        // BOOT_COMPLETE_NO_ENCRYPTION after factory reset.
-        FACTORY_RESET_BOOT_COMPLETE_NO_ENCRYPTION = 7;
-        // BOOT_COMPLETE_POST_DECRYPT after factory reset.
-        FACTORY_RESET_BOOT_COMPLETE_POST_DECRYPT = 8;
-        // BOOT_COMPLETE after OTA.
-        OTA_BOOT_COMPLETE = 9;
-        // BOOT_COMPLETE_NO_ENCRYPTION after OTA.
-        OTA_BOOT_COMPLETE_NO_ENCRYPTION = 10;
-        // BOOT_COMPLETE_POST_DECRYPT after OTA.
-        OTA_BOOT_COMPLETE_POST_DECRYPT = 11;
-        // Time when the system starts sending LOCKED_BOOT_COMPLETED broadcast.
-        // Logged from  f/b/services/.../UserController.java
-        FRAMEWORK_LOCKED_BOOT_COMPLETED = 12;
-        // Time when the system starts sending BOOT_COMPLETED broadcast.
-        // Logged from  f/b/services/.../UserController.java
-        FRAMEWORK_BOOT_COMPLETED = 13;
-        // Time when the package manager starts init.
-        // Logged from f/b/services/.../SystemServer.java
-        PACKAGE_MANAGER_INIT_START = 14;
-        // Time when package manager is ready
-        // Logged from f/b/services/.../SystemServer.java
-        PACKAGE_MANAGER_INIT_READY = 15;
-        // Represents the time when user has entered unlock credential for system with user pin.
-        // Logged from bootstat.
-        POST_DECRYPT = 16;
-        // Represents the start of zygote's init.
-        // Logged from zygote itself.
-        ZYGOTE_INIT_START = 17;
-        // Represents the start of secondary zygote's init.
-        // TODO: add logging to zygote
-        SECONDARY_ZYGOTE_INIT_START = 18;
-        // Represents the start of system server's init.
-        // Logged from f/b/services/.../SystemServer.java
-        SYSTEM_SERVER_INIT_START = 19;
-        // Represents the completion of system server's init.
-        // Logged from f/b/services/.../SystemServer.java
-        SYSTEM_SERVER_READY = 20;
-        // Represents the start of launcher during boot-up.
-        // TODO: add logging
-        LAUNCHER_START = 21;
-        // Represents the completion of launcher's initial rendering. User can use other apps from
-        // launcher from this point.
-        // TODO: add logging
-        LAUNCHER_SHOWN = 22;
-    }
-
-    // Type of the event.
-    optional ElapsedTimeEvent event = 1;
-    // Time since bootup for the event.
-    // It should be acquired from SystemClock elapsedRealtime() call or equivalent.
-    optional int64 time_millis = 2;
-}
-
-/**
- * Boot time events with UTC time.
- *
- * Logged from: bootstat and various system server components. Check each enums for details.
- */
-message BootTimeEventUtcTime {
-    enum UtcTimeEvent {
-        UNKNOWN = 0;
-        // Time of the bootstat's marking of 1st boot after the last factory reset.
-        // Logged from bootstat.
-        FACTORY_RESET_RESET_TIME = 1;
-        // The time when bootstat records FACTORY_RESET_* events. This is close to
-        // BOOT_COMPLETE time for the current bootup.
-        // Logged from bootstat.
-        FACTORY_RESET_CURRENT_TIME = 2;
-        // DUplicate of FACTORY_RESET_RESET_TIME added for debugging purpose.
-        // Logged from bootstat.
-        FACTORY_RESET_RECORD_VALUE = 3;
-    }
-
-    // Type of the event.
-    optional UtcTimeEvent event = 1;
-    // UTC time for the event.
-    optional int64 utc_time_secs = 2;
-}
-
-/**
- * Boot time events representing specific error code during bootup.
- * Meaning of error code can be different per each event type.
- *
- * Logged from: bootstat and various system server components. Check each enums for details.
- */
-message BootTimeEventErrorCode {
-    enum ErrorCodeEvent {
-        UNKNOWN = 0;
-        // Linux error code for time() call to get the current UTC time.
-        // Logged from bootstat.
-        FACTORY_RESET_CURRENT_TIME_FAILURE = 1;
-        // Represents UmountStat before the reboot for the current boot up. Error codes defined
-        // as UMOUNT_STAT_* from init/reboot.cpp.
-        // Logged from f/b/services/.../BootReceiver.java.
-        SHUTDOWN_UMOUNT_STAT = 2;
-        // Reprepsents fie system mounting error code of /data partition for the current boot.
-        // Error codes defined as combination of FsStatFlags from system/core/fs_mgr/fs_mgr.cpp.
-        // Logged from f/b/services/.../BootReceiver.java.
-        FS_MGR_FS_STAT_DATA_PARTITION = 3;
-    }
-
-    // Type of the event.
-    optional ErrorCodeEvent event = 1;
-    // error code defined per each event type.
-    // For example, this can have a value of FsStatFlags.FS_STAT_FULL_MOUNT_FAILED for the event of
-    // FS_MGR_FS_STAT.
-    optional int32 error_code = 2;
-}
-
-/**
- * Collects Virtual A/B statistics related to the use of dm-snapshot performed
- * after an OTA.
- *
- * Logged from:
- *  - system/update_engine/cleanup_previous_update_action.cc
- */
-message SnapshotMergeReported {
-    // Keep in sync with
-    // system/core/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
-    enum UpdateState {
-        // No update or merge is in progress.
-        NONE = 0;
-        // An update is applying; snapshots may already exist.
-        INITIATED = 1;
-        // An update is pending, but has not been successfully booted yet.
-        UNVERIFIED = 2;
-        // The kernel is merging in the background.
-        MERGING = 3;
-        // Post-merge cleanup steps could not be completed due to a transient
-        // error, but the next reboot will finish any pending operations.
-        MERGE_NEEDS_REBOOT = 4;
-        // Merging is complete, and needs to be acknowledged.
-        MERGE_COMPLETED = 5;
-        // Merging failed due to an unrecoverable error.
-        MERGE_FAILED = 6;
-        // The update was implicitly cancelled, either by a rollback or a flash
-        // operation via fastboot. This state can only be returned by WaitForMerge.
-        CANCELLED = 7;
-    };
-
-    // Status of the update after the merge attempts.
-    optional UpdateState final_state = 1;
-
-    // Time to complete a merge operation in milliseconds.
-    // A negative value corresponds to the case in which the merge operation
-    // was interrupted and resumed (e.g. in case of a system reboot during the
-    // merge).
-    optional int64 duration_millis = 2;
-
-    // Number of reboots that occurred after issuing and before completing the
-    // merge of all the snapshot devices.
-    optional int32 intermediate_reboots = 3;
-
-    // The device has been upgraded to Virtual A/B.
-    optional bool is_vab_retrofit = 4;
-
-    // Space that has been temporarily allocated in the /data partition
-    // containing the dm-snapshot's copy-on-write data generated during a
-    // Virtual A/B update.
-    optional int64 cow_file_size_bytes = 5;
-}
-
-/**
- * Event representing when BlobStoreManager.Session#commit() is called
- *
- * Logged from:
- *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
- */
-message BlobCommitted {
-    // Uid of the Blob committer
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Id of the Blob committed
-    optional int64 blob_id = 2;
-
-    // Size of the Blob
-    optional int64 size = 3;
-
-    enum Result {
-        UNKNOWN = 0;
-        // Commit Succeeded
-        SUCCESS = 1;
-        // Commit Failed: Error occurred during commit
-        ERROR_DURING_COMMIT = 2;
-        // Commit Failed: Digest of the data did not match Blob digest
-        DIGEST_MISMATCH = 3;
-        // Commit Failed: Allowed count limit exceeded
-        COUNT_LIMIT_EXCEEDED = 4;
-    }
-    optional Result result = 4;
-}
-
-/**
- * Event representing when BlobStoreManager#acquireLease() is called
- *
- * Logged from:
- *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
- */
-message BlobLeased{
-    // Uid of the Blob leasee
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Id of the Blob leased or 0 if the Blob does not exist
-    optional int64 blob_id = 2;
-
-    // Size of the Blob or 0 if the Blob does not exist
-    optional int64 size = 3;
-
-    enum Result {
-        UNKNOWN = 0;
-        // Lease Succeeded
-        SUCCESS = 1;
-        // Lease Failed: Blob does not exist
-        BLOB_DNE = 2;
-        // Lease Failed: Leasee does not have access to the Blob
-        ACCESS_NOT_ALLOWED = 3;
-        // Lease Failed: Leasee requested an invalid expiry duration
-        LEASE_EXPIRY_INVALID = 4;
-        // Lease Failed: Leasee has exceeded the total data lease limit
-        DATA_SIZE_LIMIT_EXCEEDED = 5;
-        // Leasee Failed: Allowed count limit exceeded
-        COUNT_LIMIT_EXCEEDED = 6;
-    }
-    optional Result result = 4;
-}
-
-/**
- * Event representing when BlobStoreManager#openBlob() is called
- *
- * Logged from:
- *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
- */
-message BlobOpened{
-    // Uid of the Blob opener
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Id of the Blob opened or 0 if the Blob does not exist
-    optional int64 blob_id = 2;
-
-    // Size of the Blob or 0 if the Blob does not exist
-    optional int64 size = 3;
-
-    enum Result {
-        UNKNOWN = 0;
-        // Open Succeeded
-        SUCCESS = 1;
-        // Open Failed: Blob does not exist
-        BLOB_DNE = 2;
-        // Open Failed: Opener does not have access to the Blob
-        ACCESS_NOT_ALLOWED = 3;
-    }
-    optional Result result = 4;
-}
-
-/**
- * Event to track Jank for various system interactions.
- *
- * Logged from:
- *  frameworks/base/core/java/com/android/internal/jank/FrameTracker.java
- */
-message UIInteractionFrameInfoReported {
-    enum InteractionType {
-        UNKNOWN = 0;
-        NOTIFICATION_SHADE_SWIPE = 1;
-        SHADE_EXPAND_COLLAPSE_LOCK = 2;
-        SHADE_SCROLL_FLING = 3;
-        SHADE_ROW_EXPAND = 4;
-        SHADE_ROW_SWIPE = 5;
-        SHADE_QS_EXPAND_COLLAPSE = 6;
-        SHADE_QS_SCROLL_SWIPE = 7;
-        LAUNCHER_APP_LAUNCH_FROM_RECENTS = 8;
-        LAUNCHER_APP_LAUNCH_FROM_ICON = 9;
-        LAUNCHER_APP_CLOSE_TO_HOME = 10;
-        LAUNCHER_APP_CLOSE_TO_PIP = 11;
-        LAUNCHER_QUICK_SWITCH = 12;
-        SHADE_HEADS_UP_APPEAR = 13;
-        SHADE_HEADS_UP_DISAPPEAR = 14;
-        SHADE_NOTIFICATION_ADD = 15;
-        SHADE_NOTIFICATION_REMOVE = 16;
-        SHADE_APP_LAUNCH = 17;
-    }
-
-    optional InteractionType interaction_type = 1;
-
-    // Number of frames rendered during the interaction.
-    optional int64 total_frames = 2;
-
-    // Number of frames that were skipped in rendering during the interaction.
-    optional int64 missed_frames = 3;
-
-    // Maximum time it took to render a single frame during the interaction.
-    optional int64 max_frame_time_nanos = 4;
-}
-
-/**
- * Event to track various latencies in SystemUI.
- *
- * Logged from:
- *  frameworks/base/core/java/com/android/internal/util/LatencyTracker.java
- */
-message UIActionLatencyReported {
-    enum ActionType {
-        UNKNOWN = 0;
-        ACTION_EXPAND_PANEL = 1;
-        ACTION_TOGGLE_RECENTS = 2;
-        ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 3;
-        ACTION_CHECK_CREDENTIAL = 4;
-        ACTION_CHECK_CREDENTIAL_UNLOCKED = 5;
-        ACTION_TURN_ON_SCREEN = 6;
-        ACTION_ROTATE_SCREEN = 7;
-        ACTION_FACE_WAKE_AND_UNLOCK = 8;
-    }
-
-    optional ActionType action = 1;
-
-    optional int64 latency_millis = 2;
-}
-
-//////////////////////////////////////////////////////////////////////
-// Pulled atoms below this line //
-//////////////////////////////////////////////////////////////////////
-
-/**
- * Pulls bytes transferred via wifi (Sum of foreground and background usage).
- *
- * Pulled from:
- *   StatsCompanionService (using BatteryStats to get which interfaces are wifi)
- */
-message WifiBytesTransfer {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional int64 rx_bytes = 2;
-
-    optional int64 rx_packets = 3;
-
-    optional int64 tx_bytes = 4;
-
-    optional int64 tx_packets = 5;
-}
-
-/**
- * Pulls bytes transferred via wifi (separated by foreground and background usage).
- *
- * Pulled from:
- *   StatsCompanionService (using BatteryStats to get which interfaces are wifi)
- */
-message WifiBytesTransferByFgBg {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
-    optional bool is_foreground = 2;
-
-    optional int64 rx_bytes = 3;
-
-    optional int64 rx_packets = 4;
-
-    optional int64 tx_bytes = 5;
-
-    optional int64 tx_packets = 6;
-}
-
-/**
- * Pulls bytes transferred via mobile networks (Sum of foreground and background usage).
- *
- * Pulled from:
- *   StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
- */
-message MobileBytesTransfer {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional int64 rx_bytes = 2;
-
-    optional int64 rx_packets = 3;
-
-    optional int64 tx_bytes = 4;
-
-    optional int64 tx_packets = 5;
-}
-
-/**
- * Pulls bytes transferred via mobile networks (separated by foreground and background usage).
- *
- * Pulled from:
- *   StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
- */
-message MobileBytesTransferByFgBg {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // 1 denotes foreground and 0 denotes background. This is called Set in
-    // NetworkStats.
-    optional bool is_foreground = 2;
-
-    optional int64 rx_bytes = 3;
-
-    optional int64 rx_packets = 4;
-
-    optional int64 tx_bytes = 5;
-
-    optional int64 tx_packets = 6;
-}
-
-/**
- * Used for pull network statistics via mobile|wifi networks, and sliced by interesting dimensions.
- * Note that the data is expected to be sliced into more dimensions in future. In other words,
- * the caller must not assume any row of data is one full report when filtering with a set of
- * matching conditions, because future data may represent with multiple rows what is currently
- * represented by one.
- * To avoid being broken by future slicing, callers must take care to aggregate rows even if they
- * query all the existing columns.
- *
- * Pulled from:
- *   StatsPullAtomService (using NetworkStatsService to get NetworkStats)
- */
-message DataUsageBytesTransfer {
-    // State of this record. Should be NetworkStats#SET_DEFAULT or NetworkStats#SET_FOREGROUND to
-    // indicate the foreground state, or NetworkStats#SET_ALL to indicate the record is for all
-    // states combined, not including debug states. See NetworkStats#SET_*.
-    optional int32 state = 1;
-
-    optional int64 rx_bytes = 2;
-
-    optional int64 rx_packets = 3;
-
-    optional int64 tx_bytes = 4;
-
-    optional int64 tx_packets = 5;
-
-    // Radio Access Technology (RAT) type of this record, should be one of
-    // TelephonyManager#NETWORK_TYPE_* constants, or NetworkTemplate#NETWORK_TYPE_ALL to indicate
-    // the record is for all rat types combined.
-    optional int32 rat_type = 6;
-
-    // Mcc/Mnc read from sim if the record is for a specific subscription, null indicates the
-    // record is combined across subscriptions.
-    optional string sim_mcc = 7;
-    optional string sim_mnc = 8;
-
-    // Allows mobile virtual network operators (MVNOs) to be identified with individual IDs.
-    // See TelephonyManager#getSimCarrierId.
-    optional int32 carrier_id = 9;
-
-    // Enumeration of opportunistic states with an additional ALL state indicates the record is
-    // combined regardless of the boolean value in its field.
-    enum DataSubscriptionState {
-        UNKNOWN = 0; // For server side backward compatibility.
-        ALL = 1;
-        OPPORTUNISTIC = 2;
-        NOT_OPPORTUNISTIC = 3;
-    }
-    // Mark whether the subscription is an opportunistic data subscription, and ALL indicates the
-    // record is combined across opportunistic data subscriptions.
-    // See {@link SubscriptionManager#setOpportunistic}.
-    optional DataSubscriptionState opportunistic_data_sub = 10;
-
-    // Indicate whether NR is connected, server side could use this with RAT type to determine if
-    // the record is for 5G NSA (Non Stand Alone) mode, where the primary cell is still LTE and
-    // network allocates a secondary 5G cell so telephony reports RAT = LTE along with NR state as
-    // connected.
-    optional bool is_nr_connected = 11;
-}
-
-/**
- * Pulls bytes transferred via bluetooth. It is pulled from Bluetooth controller.
- *
- * Pulled from:
- *   StatsCompanionService
- */
-message BluetoothBytesTransfer {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional int64 rx_bytes = 2;
-
-    optional int64 tx_bytes = 3;
-}
-
-/**
- * Pulls the kernel wakelock durations. This atom is adapted from
- * android/internal/os/KernelWakelockStats.java
- *
- * Pulled from:
- *   StatsCompanionService using KernelWakelockReader.
- */
-message KernelWakelock {
-    optional string name = 1;
-
-    optional int32 count = 2;
-
-    optional int32 version = 3;
-
-    optional int64 time_micros = 4;
-}
-
-/**
- * Pulls low power state information. If power.stats HAL is not available, this
- * includes platform and subsystem sleep state information,
- * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState
- * as defined in:
- *   hardware/interfaces/power/1.0/types.hal
- *   hardware/interfaces/power/1.1/types.hal
- * If power.stats HAL is available, this includes PowerEntityStateResidencyResult
- * as defined in:
- *   hardware/interfaces/power/stats/1.0/types.hal
- */
-message SubsystemSleepState {
-    // Subsystem name
-    optional string subsystem_name = 1;
-    // For PlatformLowPowerStats (hal 1.0), this is the voter name, which could be empty.
-    // For SubsystemLowPowerStats (hal 1.1), this is the sleep state name.
-    // For PowerEntityStateResidencyResult (hal power/stats/1.0) this is the
-    //    powerEntityStateName from the corresponding PowerEntityStateInfo.
-    optional string subname = 2;
-    // The number of times it entered, or voted for entering the sleep state
-    optional uint64 count = 3;
-    // The length of time spent in, or spent voting for, the sleep state
-    optional uint64 time_millis = 4;
-}
-
-/**
- * Pulls on-device power measurement information.
- * Data defined by hardware/interfaces/power/stats/1.0/types.hal.
- * Pulled from:
- *   frameworks/base/cmds/statsd/src/external/PowerStatsPuller.cpp
- */
-message OnDevicePowerMeasurement {
-    // Name of the subsystem (to which the rail belongs).
-    optional string subsystem_name = 1;
-
-    // Rail name. The rail lies within the subsystem.
-    optional string rail_name = 2;
-
-    // Time (in ms since boot) at which the rail energy value was measured.
-    // This may differ slightly from the time that statsd logs this information.
-    optional uint64 measurement_timestamp_millis = 3;
-
-    // Accumulated energy used via the rail since device boot in uWs.
-    optional uint64 energy_microwatt_secs = 4;
-}
-
-/**
- * Pulls Cpu time per frequency.
- * Pulls the time the cpu spend on the frequency index. Frequency index
- * starts from highest to lowest. The value should be monotonically
- * increasing since boot. However, if there is a cpu
- * hotplug event, the value would be reset as well.
- */
-message CpuTimePerFreq {
-    optional uint32 cluster = 1;
-    optional uint32 freq_index = 2;
-    optional uint64 time_millis = 3;
-}
-
-/**
- * Pulls Cpu Time Per Uid.
- * Note that isolated process uid time should be attributed to host uids.
- */
-message CpuTimePerUid {
-    optional int32 uid = 1 [(is_uid) = true];
-    optional uint64 user_time_micros = 2;
-    optional uint64 sys_time_micros = 3;
-}
-
-/**
- * Pulls Cpu Time Per Uid per frequency.
- * Note that isolated process uid time should be attributed to host uids.
- * For each uid, we order the time by descending frequencies.
- */
-message CpuTimePerUidFreq {
-    optional int32 uid = 1 [(is_uid) = true];
-    optional uint32 freq_index = 2;
-    optional uint64 time_millis = 3;
-}
-
-/**
- * Pulls Wifi Controller Activity Energy Info
- */
-message WifiActivityInfo {
-    // timestamp(wall clock) of record creation
-    optional uint64 timestamp_millis = 1;
-    // stack reported state
-    // TODO: replace this with proto enum
-    optional int32 stack_state = 2;
-    // tx time in millis
-    optional uint64 controller_tx_time_millis = 3;
-    // rx time in millis
-    optional uint64 controller_rx_time_millis = 4;
-    // idle time in millis
-    optional uint64 controller_idle_time_millis = 5;
-    // product of current(mA), voltage(V) and time(ms)
-    optional uint64 controller_energy_used = 6;
-}
-
-/**
- * Pulls Modem Activity Energy Info
- */
-message ModemActivityInfo {
-    // timestamp(wall clock) of record creation
-    optional uint64 timestamp_millis = 1;
-    // sleep time in millis.
-    optional uint64 sleep_time_millis = 2;
-    // idle time in millis
-    optional uint64 controller_idle_time_millis = 3;
-    /**
-     * Tx power index
-     * index 0 = tx_power < 0dBm
-     * index 1 = 0dBm < tx_power < 5dBm
-     * index 2 = 5dBm < tx_power < 15dBm
-     * index 3 = 15dBm < tx_power < 20dBm
-     * index 4 = tx_power > 20dBm
-     */
-    // tx time in ms at power level 0
-    optional uint64 controller_tx_time_pl0_millis = 4;
-    // tx time in ms at power level 1
-    optional uint64 controller_tx_time_pl1_millis = 5;
-    // tx time in ms at power level 2
-    optional uint64 controller_tx_time_pl2_millis = 6;
-    // tx time in ms at power level 3
-    optional uint64 controller_tx_time_pl3_millis = 7;
-    // tx time in ms at power level 4
-    optional uint64 controller_tx_time_pl4_millis = 8;
-    // rx time in ms at power level 5
-    optional uint64 controller_rx_time_millis = 9;
-    // product of current(mA), voltage(V) and time(ms)
-    optional uint64 energy_used = 10 [deprecated=true];
-}
-
-/**
- * Pulls Bluetooth Activity Energy Info
- * Note: BluetoothBytesTransfer is pulled at the same time from the controller.
- */
-message BluetoothActivityInfo {
-    // timestamp(wall clock) of record creation
-    optional uint64 timestamp_millis = 1;
-    // bluetooth stack state
-    optional int32 bluetooth_stack_state = 2;
-    // tx time in millis
-    optional uint64 controller_tx_time_millis = 3;
-    // rx time in millis
-    optional uint64 controller_rx_time_millis = 4;
-    // idle time in millis
-    optional uint64 controller_idle_time_millis = 5;
-    // product of current(mA), voltage(V) and time(ms)
-    optional uint64 energy_used = 6;
-}
-
-/*
- * Logs the memory stats for a process.
- *
- * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService).
- */
-message ProcessMemoryState {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name.
-    // Usually package name, "system" for system server.
-    // Provided by ActivityManagerService.
-    optional string process_name = 2;
-
-    // Current OOM score adjustment. Value read from ProcessRecord.
-    optional int32 oom_adj_score = 3;
-
-    // # of page-faults
-    optional int64 page_fault = 4;
-
-    // # of major page-faults
-    optional int64 page_major_fault = 5;
-
-    // RSS
-    // Value is read from memory.stat, field total_rss if per-app memory
-    // cgroups are enabled. Otherwise, value from /proc/pid/stat.
-    optional int64 rss_in_bytes = 6;
-
-    // CACHE
-    // Value is read from memory.stat, field total_cache if per-app memory
-    // cgroups are enabled. Otherwise, 0.
-    optional int64 cache_in_bytes = 7;
-
-    // SWAP
-    // Value is read from memory.stat, field total_swap if per-app memory
-    // cgroups are enabled. Otherwise, 0.
-    optional int64 swap_in_bytes = 8;
-
-    // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always -1.
-    optional int64 rss_high_watermark_in_bytes = 9 [deprecated = true];
-
-    // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
-    optional int64 start_time_nanos = 10 [deprecated = true];
-
-    // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
-    optional int32 anon_rss_and_swap_in_kilobytes = 11 [deprecated = true];
-}
-
-/*
- * Logs the memory high-water mark for a process.
- *
- * Pulled from StatsCompanionService for all managed processes (from ActivityManagerServie)
- * and for selected native processes.
- *
- * Pulling this atom resets high-water mark counters for all processes.
- */
-message ProcessMemoryHighWaterMark {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name.
-    // Usually package name or process cmdline.
-    // Provided by ActivityManagerService or read from /proc/PID/cmdline.
-    optional string process_name = 2;
-
-    // Deprecated: use rss_high_water_mark_in_kilobytes instead. This field is
-    // computed by converting kilobytes to bytes.
-    optional int64 rss_high_water_mark_in_bytes = 3 [deprecated = true];
-
-    // RSS high-water mark. Peak RSS usage of the process. Read from the VmHWM field in
-    // /proc/PID/status.
-    optional int32 rss_high_water_mark_in_kilobytes = 4;
-}
-
-/*
- * Logs the memory stats for a process.
- *
- * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService)
- * and for selected native processes.
- */
-message ProcessMemorySnapshot {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name.
-    // Usually package name or process cmdline.
-    // Provided by ActivityManagerService or read from /proc/PID/cmdline.
-    optional string process_name = 2;
-
-    // The pid of the process.
-    // Allows to disambiguate instances of the process.
-    optional int32 pid = 3;
-
-    // The current OOM score adjustment value.
-    // Read from ProcessRecord for managed processes.
-    // Placeholder -1001 (OOM_SCORE_ADJ_MIN - 1, outside of allowed range) for native ones.
-    optional int32 oom_score_adj = 4;
-
-    // The current RSS of the process.
-    // VmRSS from /proc/pid/status.
-    optional int32 rss_in_kilobytes = 5;
-
-    // The current anon RSS of the process.
-    // RssAnon from /proc/pid/status.
-    optional int32 anon_rss_in_kilobytes = 6;
-
-    // The current swap size of the process.
-    // VmSwap from /proc/pid/status.
-    optional int32 swap_in_kilobytes = 7;
-
-    // The sum of rss_in_kilobytes and swap_in_kilobytes.
-    optional int32 anon_rss_and_swap_in_kilobytes = 8;
-}
-
-/*
- * Elapsed real time from SystemClock.
- */
-message SystemElapsedRealtime {
-    optional uint64 time_millis = 1;
-}
-
-/*
- * Up time from SystemClock.
- */
-message SystemUptime {
-    // Milliseconds since the system was booted.
-    // This clock stops when the system enters deep sleep (CPU off, display dark, device waiting
-    // for external input).
-    // It is not affected by clock scaling, idle, or other power saving mechanisms.
-    optional uint64 uptime_millis = 1;
-}
-
-/*
- * Reads from /proc/uid_concurrent_active_time which has the format:
- * active: X (X is # cores)
- * [uid0]: [time-0] [time-1] [time-2] ... (# entries = # cores)
- * [uid1]: [time-0] [time-1] [time-2] ... ...
- * ...
- * Time-N means the CPU time a UID spent running concurrently with N other processes.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-message CpuActiveTime {
-    optional int32 uid = 1 [(is_uid) = true];
-    optional uint64 time_millis = 2;
-}
-
-/**
- * Reads from /proc/uid_concurrent_policy_time which has the format:
- * policy0: X policy4: Y (there are X cores on policy0, Y cores on policy4)
- * [uid0]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
- * [uid1]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
- * ...
- * Time-X-Y means the time a UID spent on clusterX running concurrently with Y other processes.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-message CpuClusterTime {
-    optional int32 uid = 1 [(is_uid) = true];
-    optional int32 cluster_index = 2;
-    optional uint64 time_millis = 3;
-}
-
-/*
- * Pulls free disk space, for data, system partition and temporary directory.
- */
-message DiskSpace {
-    // available bytes in data partition
-    optional uint64 data_available_bytes = 1;
-    // available bytes in system partition
-    optional uint64 system_available_bytes = 2;
-    // available bytes in download cache or temp directories
-    optional uint64 temp_available_bytes = 3;
-}
-
-/**
- * Pulls battery coulomb counter, which is the remaining battery charge in uAh.
- *
- * Pulled from StatsCompanionService.java
- */
-message RemainingBatteryCapacity {
-    optional int32 charge_micro_ampere_hour = 1;
-}
-
-/**
- * Pulls battery capacity, which is the battery capacity when full in uAh.
- * Pulled from:
- *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
- */
-message FullBatteryCapacity {
-    optional int32 capacity_micro_ampere_hour = 1;
-}
-
-/**
- * Pulls battery voltage.
- * Pulled from:
- *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
- */
-message BatteryVoltage {
-    // The voltage of the battery, in millivolts.
-    optional int32 voltage_millivolt = 1;
-}
-
-/**
- * Pulls battery level (percent full, from 0 to 100).
- *
- * Pulled from:
- *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
- */
-message BatteryLevel {
-    // Battery level. Should be in [0, 100].
-    optional int32 battery_level = 1;
-}
-
-/**
- * Pulls the temperature of various parts of the device.
- * The units are tenths of a degree Celsius. Eg: 30.3C is reported as 303.
- *
- * Pulled from StatsCompanionService.java
- */
-message Temperature {
-    // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY, BCL_.
-    optional android.os.TemperatureTypeEnum sensor_location = 1;
-
-    // The name of the temperature source. Eg. CPU0
-    optional string sensor_name = 2;
-
-    // Temperature in tenths of a degree C.
-    // For BCL, it is decimillivolt, decimilliamps, and percentage * 10.
-    optional int32 temperature_deci_celsius = 3;
-
-    // Relative severity of the throttling, see enum definition.
-    optional android.os.ThrottlingSeverityEnum severity = 4;
-}
-
-/**
- * Pulls the statistics of calls to Binder.
- *
- * Binder stats will be reset every time the data is pulled. It means it can only be pulled by one
- * config on the device.
- *
- * Next tag: 15
- */
-message BinderCalls {
-    // UID of the process responsible for the binder transaction. It will be set if the process
-    // executing the binder transaction attribute the transaction to another uid using
-    // Binder.setThreadWorkSource().
-    //
-    // If not set, the value will be -1.
-    optional int32 uid = 1 [(is_uid) = true];
-    // UID of the process executing the binder transaction.
-    optional int32 direct_caller_uid = 14;
-    // Fully qualified class name of the API call.
-    //
-    // This is a system server class name.
-    //
-    // TODO(gaillard): figure out if binder call stats includes data from isolated uids, if a uid
-    // gets recycled and we have isolated uids, we might attribute the data incorrectly.
-    // TODO(gaillard): there is a high dimensions cardinality, figure out if we should drop the less
-    // commonly used APIs.
-    optional string service_class_name = 2;
-    // Method name of the API call. It can also be a transaction code if we cannot
-    // resolve it to a name. See Binder#getTransactionName.
-    //
-    // This is a system server method name.
-    optional string service_method_name = 3;
-    // Total number of API calls.
-    optional int64 call_count = 4;
-    // True if the screen was interactive PowerManager#isInteractive at the end of the call.
-    optional bool screen_interactive = 13;
-    // Total number of API calls we have data recorded for. If we collected data for all the calls,
-    // call_count will be equal to recorded_call_count.
-    //
-    // If recorded_call_count is different than call_count, it means data collection has been
-    // sampled. All the fields below will be sampled in this case.
-    optional int64 recorded_call_count = 12;
-    // Number of exceptions thrown by the API.
-    optional int64 recorded_exception_count = 5;
-    // Total latency of all API calls.
-    // Average can be computed using total_latency_micros / recorded_call_count.
-    optional int64 recorded_total_latency_micros = 6;
-    // Maximum latency of one API call.
-    optional int64 recorded_max_latency_micros = 7;
-    // Total CPU usage of all API calls.
-    // Average can be computed using total_cpu_micros / recorded_call_count.
-    // Total can be computed using total_cpu_micros / recorded_call_count * call_count.
-    optional int64 recorded_total_cpu_micros = 8;
-    // Maximum CPU usage of one API call.
-    optional int64 recorded_max_cpu_micros = 9;
-    // Maximum parcel reply size of one API call.
-    optional int64 recorded_max_reply_size_bytes = 10;
-    // Maximum parcel request size of one API call.
-    optional int64 recorded_max_request_size_bytes = 11;
-}
-
-/**
- * Pulls the statistics of exceptions during calls to Binder.
- *
- * Binder stats are cumulative from boot unless somebody reset the data using
- * > adb shell dumpsys binder_calls_stats --reset
- */
-message BinderCallsExceptions {
-    // Exception class name, e.g. java.lang.IllegalArgumentException.
-    //
-    // This is an exception class name thrown by the system server.
-    optional string exception_class_name = 1;
-    // Total number of exceptions.
-    optional int64 exception_count = 2;
-}
-
-/**
- * Pulls the statistics of message dispatching on HandlerThreads.
- *
- * Looper stats will be reset every time the data is pulled. It means it can only be pulled by one
- * config on the device.
- *
- * Next tag: 11
- */
-message LooperStats {
-    // The uid that made a call to the System Server and caused the message to be enqueued.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Fully qualified class name of the handler target class.
-    //
-    // This field does not contain PII. This is a system server class name.
-    optional string handler_class_name = 2;
-
-    // The name of the thread that runs the Looper.
-    //
-    // This field does not contain PII. This is a system server thread name.
-    optional string looper_thread_name = 3;
-
-    // The name of the dispatched message.
-    //
-    // This field does not contain PII. This is a system server constant or class
-    // name.
-    optional string message_name = 4;
-
-    // Total number of successfully dispatched messages.
-    optional int64 message_count = 5;
-
-    // Total number of messages that failed dispatching.
-    optional int64 exception_count = 6;
-
-    // Total number of processed messages we have data recorded for. If we
-    // collected data for all the messages, message_count will be equal to
-    // recorded_message_count.
-    //
-    // If recorded_message_count is different than message_count, it means data
-    // collection has been sampled. The fields below will be sampled in this case.
-    optional int64 recorded_message_count = 7;
-
-    // Total latency of all processed messages.
-    // Average can be computed using recorded_total_latency_micros /
-    // recorded_message_count.
-    optional int64 recorded_total_latency_micros = 8;
-
-    // Total CPU usage of all processed message.
-    // Average can be computed using recorded_total_cpu_micros /
-    // recorded_message_count. Total can be computed using
-    // recorded_total_cpu_micros / recorded_message_count * message_count.
-    optional int64 recorded_total_cpu_micros = 9;
-
-    // True if the screen was interactive PowerManager#isInteractive at the end of the call.
-    optional bool screen_interactive = 10;
-
-    // Max recorded CPU usage of all processed messages.
-    optional int64 recorded_max_cpu_micros = 11;
-
-    // Max recorded latency of all processed messages.
-    optional int64 recorded_max_latency_micros = 12;
-
-    // Total number of messages we tracked the dispatching delay for. If we
-    // collected data for all the messages, message_count will be equal to
-    // recorded_delay_message_count.
-    //
-    // If recorded_delay_message_count is different than message_count, it means data
-    // collection has been sampled or/and not all messages specified the target dispatch time.
-    // The fields below will be sampled in this case.
-    optional int64 recorded_delay_message_count = 13;
-
-    // Total dispatching delay of all processed messages.
-    // Calculated as a difference between the target dispatching time (Message.when)
-    // and the actual dispatching time.
-    // Average can be computed using recorded_total_delay_millis / recorded_delay_message_count.
-    optional int64 recorded_total_delay_millis = 14;
-
-    // Max dispatching delay of all processed messages.
-    // Calculated as a difference between the target dispatching time (Message.when)
-    // and the actual dispatching time.
-    optional int64 recorded_max_delay_millis = 15;
-}
-
-/**
- * Pulls disk information, such as write speed and latency.
- */
-message DiskStats {
-    // Time taken to open, write 512B to, and close a file.
-    // -1 if error performing the check.
-    optional int64 data_write_latency_millis = 1;
-
-    optional bool file_based_encryption = 2;
-
-    // Recent disk write speed in kB/s.
-    // -1 if error querying storageed.
-    // 0 if data is unavailable.
-    optional int32 recent_disk_write_speed = 3;
-}
-
-
-/**
- * Free and total bytes of the Data, Cache, and System partition.
- */
-message DirectoryUsage {
-    enum Directory {
-        UNKNOWN = 0;
-        DATA = 1;
-        CACHE = 2;
-        SYSTEM = 3;
-    }
-    optional Directory directory = 1;
-    optional int64 free_bytes = 2;
-    optional int64 total_bytes = 3;
-}
-
-
-/**
- * Size of an application: apk size, data size, and cache size.
- * Reads from a cached file produced daily by DiskStatsLoggingService.java.
- * Information is only reported for apps with the primary user (user 0).
- * Sizes are aggregated by package name.
- */
-message AppSize {
-    // Including uids will involve modifying diskstats logic.
-    optional string package_name = 1;
-    // App size in bytes. -1 if unavailable.
-    optional int64 app_size_bytes = 2;
-    // App data size in bytes. -1 if unavailable.
-    optional int64 app_data_size_bytes = 3;
-    // App cache size in bytes. -1 if unavailable.
-    optional int64 app_cache_size_bytes = 4;
-    // Time that the cache file was produced.
-    // Uses System.currentTimeMillis(), which is wall clock time.
-    optional int64 cache_time_millis = 5;
-}
-
-
-/**
- * Size of a particular category. Eg: photos, videos.
- * Reads from a cached file produced daily by DiskStatsLoggingService.java.
- */
-message CategorySize {
-    enum Category {
-        UNKNOWN = 0;
-        APP_SIZE = 1;
-        APP_DATA_SIZE = 2;
-        APP_CACHE_SIZE = 3;
-        PHOTOS = 4;
-        VIDEOS = 5;
-        AUDIO = 6;
-        DOWNLOADS = 7;
-        SYSTEM = 8;
-        OTHER = 9;
-    }
-    optional Category category = 1;
-    // Category size in bytes.
-    optional int64 size_bytes = 2;
-    // Time that the cache file was produced.
-    // Uses System.currentTimeMillis(), which is wall clock time.
-    optional int64 cache_time_millis = 3;
-}
-
-/**
- * Pulls per uid I/O stats. The stats are cumulative since boot.
- *
- * Read/write bytes are I/O events from a storage device
- * Read/write chars are data requested by read/write syscalls, and can be
- *   satisfied by caching.
- *
- * Pulled from StatsCompanionService, which reads proc/uid_io/stats.
- */
-message DiskIo {
-    optional int32 uid = 1 [(is_uid) = true];
-    optional int64 fg_chars_read = 2;
-    optional int64 fg_chars_write = 3;
-    optional int64 fg_bytes_read = 4;
-    optional int64 fg_bytes_write = 5;
-    optional int64 bg_chars_read = 6;
-    optional int64 bg_chars_write = 7;
-    optional int64 bg_bytes_read = 8;
-    optional int64 bg_bytes_write = 9;
-    optional int64 fg_fsync = 10;
-    optional int64 bg_fsync= 11;
-}
-
-
-/**
- * Pulls the number of fingerprints for each user.
- *
- * Pulled from StatsCompanionService, which queries <Biometric>Manager.
- */
-message NumFingerprintsEnrolled {
-    // The associated user. Eg: 0 for owners, 10+ for others.
-    // Defined in android/os/UserHandle.java
-    optional int32 user = 1;
-    // Number of fingerprints registered to that user.
-    optional int32 num_fingerprints_enrolled = 2;
-}
-
-/**
- * Pulls the number of faces for each user.
- *
- * Pulled from StatsCompanionService, which queries <Biometric>Manager.
- */
-message NumFacesEnrolled {
-    // The associated user. Eg: 0 for owners, 10+ for others.
-    // Defined in android/os/UserHandle.java
-    optional int32 user = 1;
-    // Number of faces registered to that user.
-    optional int32 num_faces_enrolled = 2;
-}
-/**
- * A mapping of role holder -> role
- */
-message RoleHolder {
-    // uid of the role holder
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // package name of the role holder
-    optional string package_name = 2;
-
-    // the role held
-    optional string role = 3;
-}
-
-message AggStats {
-    // These are all in byte resolution.
-    optional int64 min = 1 [deprecated = true];
-    optional int64 average = 2 [deprecated = true];
-    optional int64 max = 3 [deprecated = true];
-
-    // These are all in kilobyte resolution. Can fit in int32, so smaller on the wire than the above
-    // int64 fields.
-    optional int32 mean_kb = 4;
-    optional int32 max_kb = 5;
-}
-
-// A reduced subset of process states; reducing the number of possible states allows more
-// aggressive device-side aggregation of statistics and hence reduces metric upload size.
-enum ProcessStateAggregated {
-    PROCESS_STATE_UNKNOWN = 0;
-    // Persistent system process.
-    PROCESS_STATE_PERSISTENT = 1;
-    // Top activity; actually any visible activity.
-    PROCESS_STATE_TOP = 2;
-    // Process binding to top or a foreground service.
-    PROCESS_STATE_BOUND_TOP_OR_FGS = 3;
-    // Processing running a foreground service.
-    PROCESS_STATE_FGS = 4;
-    // Important foreground process (ime, wallpaper, etc).
-    PROCESS_STATE_IMPORTANT_FOREGROUND = 5;
-    // Important background process.
-    PROCESS_STATE_BACKGROUND = 6;
-    // Process running a receiver.
-    PROCESS_STATE_RECEIVER = 7;
-    // All kinds of cached processes.
-    PROCESS_STATE_CACHED = 8;
-}
-
-// Next tag: 13
-message ProcessStatsStateProto {
-    optional android.service.procstats.ScreenState screen_state = 1;
-
-    optional android.service.procstats.MemoryState memory_state = 2 [deprecated = true];
-
-    // this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
-    // and not frameworks/base/core/java/android/app/ActivityManager.java
-    optional android.service.procstats.ProcessState process_state = 3 [deprecated = true];
-
-    optional ProcessStateAggregated process_state_aggregated = 10;
-
-    // Millisecond uptime duration spent in this state
-    optional int64 duration_millis = 4 [deprecated = true];
-    // Same as above, but with minute resolution so it fits into an int32.
-    optional int32 duration_minutes = 11;
-
-    // Millisecond elapsed realtime duration spent in this state
-    optional int64 realtime_duration_millis = 9 [deprecated = true];
-    // Same as above, but with minute resolution so it fits into an int32.
-    optional int32 realtime_duration_minutes = 12;
-
-    // # of samples taken
-    optional int32 sample_size = 5;
-
-    // PSS is memory reserved for this process
-    optional AggStats pss = 6 [deprecated = true];
-
-    // USS is memory shared between processes, divided evenly for accounting
-    optional AggStats uss = 7 [deprecated = true];
-
-    // RSS is memory resident for this process
-    optional AggStats rss = 8;
-}
-
-// Next Tag: 8
-message ProcessStatsProto {
-    // Name of process.
-    optional string process = 1;
-
-    // Uid of the process.
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Information about how often kills occurred
-    message Kill {
-        // Count of excessive CPU kills
-        optional int32 cpu = 1;
-
-        // Count of kills when cached
-        optional int32 cached = 2;
-
-        // PSS stats during cached kill
-        optional AggStats cached_pss = 3;
-    }
-    optional Kill kill = 3 [deprecated = true];
-
-    // Time and memory spent in various states.
-    repeated ProcessStatsStateProto states = 5;
-
-    // Total time process has been running...  screen_state, memory_state, and process_state
-    // will not be set.
-    optional ProcessStatsStateProto total_running_state = 6;
-
-    // Association data for this process in this state;
-    // each entry here is one association.
-    repeated ProcessStatsAssociationProto assocs = 7;
-}
-
-// Next Tag: 6
-message ProcessStatsAssociationProto {
-    // Procss Name of the associated process (client process of service binding)
-    optional string assoc_process_name = 1;
-
-    // Package Name of the associated package (client package of service binding)
-    optional string assoc_package_name = 2 [deprecated = true];
-
-    // UID of the associated process/package (client package of service binding)
-    optional int32 assoc_uid = 5 [(is_uid) = true];
-
-    // Total count of the times this association (service binding) appeared.
-    optional int32 total_count = 3;
-
-    // Uptime total duration in seconds this association (service binding) was around.
-    optional int32 total_duration_secs = 4;
-}
-
-message PackageServiceOperationStatsProto {
-    // Operate enum: Started, Foreground, Bound, Executing
-    optional android.service.procstats.ServiceOperationState operation = 1;
-
-    // Number of times the service was in this operation.
-    optional int32 count = 2;
-
-    // Information about a state the service can be in.
-    message StateStats {
-        // Screen state enum.
-        optional android.service.procstats.ScreenState screen_state = 1;
-        // Memory state enum.
-        optional android.service.procstats.MemoryState memory_state = 2;
-
-        // duration in milliseconds.
-        optional int64 duration_millis = 3;
-        // Millisecond elapsed realtime duration spent in this state
-        optional int64 realtime_duration_millis = 4;
-    }
-    repeated StateStats state_stats = 3;
-}
-
-message PackageServiceStatsProto {
-    // Name of service component.
-    optional string service_name = 1;
-
-    // The operation stats.
-    // The package_name, package_uid, package_version, service_name will not be set to save space.
-    repeated PackageServiceOperationStatsProto operation_stats = 2;
-}
-
-message PackageAssociationSourceProcessStatsProto {
-    // Uid of the process.
-    optional int32 process_uid = 1;
-    // Process name.
-    optional string process_name = 2;
-    // Package name.
-    optional string package_name = 7;
-    // Total count of the times this association appeared.
-    optional int32 total_count = 3;
-
-    // Millisecond uptime total duration this association was around.
-    optional int64 total_duration_millis = 4;
-
-    // Total count of the times this association became actively impacting its target process.
-    optional int32 active_count = 5;
-
-    // Information on one source in this association.
-    message StateStats {
-        // Process state enum.
-        optional android.service.procstats.ProcessState process_state = 1;
-        // Millisecond uptime duration spent in this state
-        optional int64 duration_millis = 2;
-        // Millisecond elapsed realtime duration spent in this state
-        optional int64 realtime_duration_mmillis = 3;
-    }
-    repeated StateStats active_state_stats = 6;
-}
-
-message PackageAssociationProcessStatsProto {
-    // Name of the target component.
-    optional string component_name = 1;
-    // Information on one source in this association.
-    repeated PackageAssociationSourceProcessStatsProto sources = 2;
-}
-
-
-message ProcessStatsPackageProto {
-    // Name of package.
-    optional string package = 1;
-
-    // Uid of the package.
-    optional int32 uid = 2;
-
-    // Version of the package.
-    optional int64 version = 3;
-
-    // Stats for each process running with the package loaded in to it.
-    repeated ProcessStatsProto process_stats = 4;
-
-    // Stats for each of the package's services.
-    repeated PackageServiceStatsProto service_stats = 5;
-
-    // Stats for each association with the package.
-    repeated PackageAssociationProcessStatsProto association_stats = 6;
-}
-
-message ProcessStatsSectionProto {
-    // Elapsed realtime at start of report.
-    optional int64 start_realtime_millis = 1;
-
-    // Elapsed realtime at end of report.
-    optional int64 end_realtime_millis = 2;
-
-    // CPU uptime at start of report.
-    optional int64 start_uptime_millis = 3;
-
-    // CPU uptime at end of report.
-    optional int64 end_uptime_millis = 4;
-
-    // System runtime library. e.g. "libdvm.so", "libart.so".
-    optional string runtime = 5;
-
-    // whether kernel reports swapped pss.
-    optional bool has_swapped_pss = 6;
-
-    // Data completeness. e.g. "complete", "partial", shutdown", or "sysprops".
-    enum Status {
-        STATUS_UNKNOWN = 0;
-        STATUS_COMPLETE = 1;
-        STATUS_PARTIAL = 2;
-        STATUS_SHUTDOWN = 3;
-        STATUS_SYSPROPS = 4;
-    }
-    repeated Status status = 7;
-
-    // Number of pages available of various types and sizes, representation fragmentation.
-    repeated ProcessStatsAvailablePagesProto available_pages = 10;
-
-    // Stats for each process.
-    repeated ProcessStatsProto process_stats = 8;
-
-    // Stats for each package.
-    repeated ProcessStatsPackageProto package_stats = 9;
-}
-
-message ProcessStatsAvailablePagesProto {
-    // Node these pages are in (as per /proc/pagetypeinfo)
-    optional int32 node = 1;
-
-    // Zone these pages are in (as per /proc/pagetypeinfo)
-    optional string zone = 2;
-
-    // Label for the type of these pages (as per /proc/pagetypeinfo)
-    optional string label = 3;
-
-    // Distribution of number of pages available by order size.  First entry in array is
-    // order 0, second is order 1, etc.  Each order increase is a doubling of page size.
-    repeated int32 pages_per_order = 4;
-}
-
-/**
- * Pulled from ProcessStatsService.java
- */
-message ProcStats {
-    optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES];
-    // Data pulled from device into this is sometimes sharded across multiple atoms to work around
-    // a size limit. When this happens, this shard ID will contain an increasing 1-indexed integer
-    // with the number of this shard.
-    optional int32 shard_id = 2;
-}
-
-/**
- * Pulled from ProcessStatsService.java
- */
-message ProcStatsPkgProc {
-    optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES];
-}
-
-// Next Tag: 2
-message PackageRemoteViewInfoProto {
-    optional string package_name = 1;
-    // add per-package additional info here (like channels)
-}
-
-// Next Tag: 2
-message NotificationRemoteViewsProto {
-    repeated PackageRemoteViewInfoProto package_remote_view_info = 1;
-}
-
-/**
- * Pulled from NotificationManagerService.java
- */
-message NotificationRemoteViews {
-    optional NotificationRemoteViewsProto notification_remote_views = 1 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Atom that contains a list of a package's preferences, pulled from NotificationManagerService.java
- */
-message PackageNotificationPreferences {
-    // Uid under which the package is installed.
-    optional int32 uid = 1 [(is_uid) = true];
-    // Notification importance, which specifies when and how a notification is displayed.
-    // Specified under core/java/android/app/NotificationManager.java.
-    optional int32 importance = 2;
-    // Lockscreen visibility as set by the user.
-    optional int32 visibility = 3;
-    // Bitfield mask indicating what fields were locked by the user (see LockableAppfields in
-    // PreferencesHelper.java)
-    optional int32 user_locked_fields = 4;
-}
-
-/**
- * Atom that contains a list of a package's channel preferences, pulled from
- * NotificationManagerService.java.
- */
-message PackageNotificationChannelPreferences {
-    // Uid under which the package is installed.
-    optional int32 uid = 1 [(is_uid) = true];
-    // Channel's ID. Should always be available.
-    optional string channel_id = 2;
-    // Channel's name. Should always be available.
-    optional string channel_name = 3;
-    // Channel's description. Optionally set by the channel creator.
-    optional string description = 4;
-    // Notification importance, which specifies when and how a notification is displayed. Specified
-    // under core/java/android/app/NotificationManager.java.
-    optional int32 importance = 5;
-    // Bitmask representing which fields have been set by the user. See field bitmask descriptions
-    // at core/java/android/app/NotificationChannel.java
-    optional int32 user_locked_fields = 6;
-    // Indicates if the channel was deleted by the app.
-    optional bool is_deleted = 7;
-    // Indicates if the channel was marked as a conversation by the app.
-    optional bool is_conversation = 8;
-    // Indicates if the channel is a conversation that was demoted by the user.
-    optional bool is_demoted_conversation = 9;
-    // Indicates if the channel is a conversation that was marked as important by the user.
-    optional bool is_important_conversation = 10;
-}
-
-/**
- * Atom that represents an item in the list of Do Not Disturb rules, pulled from
- * NotificationManagerService.java.
- */
-message DNDModeProto {
-    enum Mode {
-        ROOT_CONFIG = -1;  // Used to distinguish the config (one per user) from the rules.
-        ZEN_MODE_OFF = 0;
-        ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
-        ZEN_MODE_NO_INTERRUPTIONS = 2;
-        ZEN_MODE_ALARMS = 3;
-    }
-    optional int32 user = 1;  // Android user ID (0, 1, 10, ...)
-    optional bool enabled = 2;  // true for ROOT_CONFIG if a manualRule is enabled
-    optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG
-    optional Mode zen_mode = 4;
-    // id is one of the system default rule IDs, or empty
-    // May also be "MANUAL_RULE" to indicate app-activation of the manual rule.
-    optional string id = 5;
-    optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other
-    optional DNDPolicyProto policy = 7 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto.
- */
-message DNDPolicyProto {
-    enum State {
-        STATE_UNSET = 0;
-        STATE_ALLOW = 1;
-        STATE_DISALLOW = 2;
-    }
-    optional State calls = 1;
-    optional State repeat_callers = 2;
-    optional State messages = 3;
-    optional State conversations = 4;
-    optional State reminders = 5;
-    optional State events = 6;
-    optional State alarms = 7;
-    optional State media = 8;
-    optional State system = 9;
-    optional State fullscreen = 10;
-    optional State lights = 11;
-    optional State peek = 12;
-    optional State status_bar = 13;
-    optional State badge = 14;
-    optional State ambient = 15;
-    optional State notification_list = 16;
-
-    enum PeopleType {
-        PEOPLE_UNSET = 0;
-        PEOPLE_ANYONE = 1;
-        PEOPLE_CONTACTS = 2;
-        PEOPLE_STARRED = 3;
-        PEOPLE_NONE = 4;
-    }
-
-    optional PeopleType allow_calls_from = 17;
-    optional PeopleType allow_messages_from = 18;
-
-    enum ConversationType {
-        CONV_UNSET = 0;
-        CONV_ANYONE = 1;
-        CONV_IMPORTANT = 2;
-        CONV_NONE = 3;
-    }
-
-    optional ConversationType allow_conversations_from = 19;
-}
-
-/**
- * Atom that contains a list of a package's channel group preferences, pulled from
- * NotificationManagerService.java.
- */
-message PackageNotificationChannelGroupPreferences {
-    // Uid under which the package is installed.
-    optional int32 uid = 1 [(is_uid) = true];
-    // Channel Group's ID. Should always be available.
-    optional string group_id = 2;
-    // Channel Group's name. Should always be available.
-    optional string group_name = 3;
-    // Channel Group's description. Optionally set by group creator.
-    optional string description = 4;
-    // Indicates if notifications from this channel group are blocked.
-    optional bool is_blocked = 5;
-    // Bitmask representing which fields have been set by the user. See field bitmask descriptions
-    // at core/java/android/app/NotificationChannelGroup.java
-    optional int32 user_locked_fields = 6;
-}
-
-message PowerProfileProto {
-    optional double cpu_suspend = 1;
-
-    optional double cpu_idle = 2;
-
-    optional double cpu_active = 3;
-
-    message CpuCluster {
-        optional int32 id = 1;
-        optional double cluster_power = 2;
-        optional int32 cores = 3;
-        repeated int64 speed = 4;
-        repeated double core_power = 5;
-    }
-
-    repeated CpuCluster cpu_cluster = 40;
-
-    optional double wifi_scan = 4;
-
-    optional double wifi_on = 5;
-
-    optional double wifi_active = 6;
-
-    optional double wifi_controller_idle = 7;
-
-    optional double wifi_controller_rx = 8;
-
-    optional double wifi_controller_tx = 9;
-
-    repeated double wifi_controller_tx_levels = 10;
-
-    optional double wifi_controller_operating_voltage = 11;
-
-    optional double bluetooth_controller_idle = 12;
-
-    optional double bluetooth_controller_rx = 13;
-
-    optional double bluetooth_controller_tx = 14;
-
-    optional double bluetooth_controller_operating_voltage = 15;
-
-    optional double modem_controller_sleep = 16;
-
-    optional double modem_controller_idle = 17;
-
-    optional double modem_controller_rx = 18;
-
-    repeated double modem_controller_tx = 19;
-
-    optional double modem_controller_operating_voltage = 20;
-
-    optional double gps_on = 21;
-
-    repeated double gps_signal_quality_based = 22;
-
-    optional double gps_operating_voltage = 23;
-
-    optional double bluetooth_on = 24;
-
-    optional double bluetooth_active = 25;
-
-    optional double bluetooth_at_cmd = 26;
-
-    optional double ambient_display = 27;
-
-    optional double screen_on = 28;
-
-    optional double radio_on = 29;
-
-    optional double radio_scanning = 30;
-
-    optional double radio_active = 31;
-
-    optional double screen_full = 32;
-
-    optional double audio = 33;
-
-    optional double video = 34;
-
-    optional double flashlight = 35;
-
-    optional double memory = 36;
-
-    optional double camera = 37;
-
-    optional double wifi_batched_scan = 38;
-
-    optional double battery_capacity = 39;
-}
-
-/**
- * power_profile.xml and other constants for power model calculations.
- * Pulled from PowerProfile.java
- */
-message PowerProfile {
-    optional PowerProfileProto power_profile = 1 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs when a user restriction was added or removed.
- *
- * Logged from:
- *   frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
- */
-message UserRestrictionChanged {
-    // The raw string of the user restriction as defined in UserManager.
-    // Allowed values are defined in UserRestrictionsUtils#USER_RESTRICTIONS.
-    optional string restriction = 1;
-    // Whether the restriction is enabled or disabled.
-    optional bool enabled = 2;
-}
-
-/**
- * Pulls process user time and system time. Puller takes a snapshot of all pids
- * in the system and returns cpu stats for those that are working at the time.
- * Dead pids will be dropped. Kernel processes are excluded.
- * Min cool-down is 5 sec.
- */
-message ProcessCpuTime {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional string process_name = 2;
-    // Process cpu time in user space, cumulative from boot/process start
-    optional int64 user_time_millis = 3;
-    // Process cpu time in system space, cumulative from boot/process start
-    optional int64 system_time_millis = 4;
-}
-
-/**
- * Pulls the CPU usage for each thread.
- *
- * Read from /proc/$PID/task/$TID/time_in_state files.
- *
- * TODO(mishaw): This is an experimental atom. Issues with big/little CPU frequencies, and
- * time_in_state files not being present on some phones, have not been addressed. These should be
- * considered before a public release.
- */
-message CpuTimePerThreadFreq {
-    // UID that owns the process.
-    optional int32 uid = 1 [(is_uid) = true];
-    // ID of the process.
-    optional int32 process_id = 2;
-    // ID of the thread.
-    optional int32 thread_id = 3;
-    // Name of the process taken from `/proc/$PID/cmdline`.
-    optional string process_name = 4;
-    // Name of the thread taken from `/proc/$PID/task/$TID/comm`
-    optional string thread_name = 5;
-
-    // Report eight different frequencies, and how much time is spent in each frequency. Frequencies
-    // are given in KHz, and time is given in milliseconds since the thread started. All eight
-    // frequencies are given here as the alternative is sending eight separate atoms. This method
-    // significantly reduces the amount of data created
-    optional int32 frequency1_khz = 6;
-    optional int32 time1_millis = 7;
-    optional int32 frequency2_khz = 8;
-    optional int32 time2_millis = 9;
-    optional int32 frequency3_khz = 10;
-    optional int32 time3_millis = 11;
-    optional int32 frequency4_khz = 12;
-    optional int32 time4_millis = 13;
-    optional int32 frequency5_khz = 14;
-    optional int32 time5_millis = 15;
-    optional int32 frequency6_khz = 16;
-    optional int32 time6_millis = 17;
-    optional int32 frequency7_khz = 18;
-    optional int32 time7_millis = 19;
-    optional int32 frequency8_khz = 20;
-    optional int32 time8_millis = 21;
-}
-
-/**
- * Pulls information about the device's build.
- */
-message BuildInformation {
-    // Build.FINGERPRINT. A string that uniquely identifies this build. Do not parse.
-    // E.g. may be composed of the brand, product, device, release, id, incremental, type, and tags.
-    optional string fingerprint = 1;
-
-    // Build.BRAND. The consumer-visible brand with which the product/hardware will be associated.
-    optional string brand = 2;
-
-    // Build.PRODUCT. The name of the overall product.
-    optional string product = 3;
-
-    // Build.DEVICE. The name of the industrial design.
-    optional string device = 4;
-
-    // Build.VERSION.RELEASE. The user-visible version string.  E.g., "1.0" or "3.4b5" or "bananas".
-    optional string version_release = 5;
-
-    // Build.ID. E.g. a label like "M4-rc20".
-    optional string id = 6;
-
-    // Build.VERSION.INCREMENTAL. The internal value used by the underlying source control to
-    // represent this build.
-    optional string version_incremental = 7;
-
-    // Build.TYPE. The type of build, like "user" or "eng".
-    optional string type = 8;
-
-    // Build.TAGS. Comma-separated tags describing the build, like "unsigned,debug".
-    optional string tags = 9;
-}
-
-/**
- * Logs information about mismatched caller for content capture.
- *
- * Logged from:
- *   frameworks/base/core/java/android/service/contentcapture/ContentCaptureService.java
- */
-message ContentCaptureCallerMismatchReported {
-    optional string intended_package = 1;
-    optional string calling_package = 2;
-}
-
-/**
- * Logs information about content capture service events.
- *
- * Logged from:
- *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
- */
-message ContentCaptureServiceEvents {
-    // The type of event.
-    enum Event {
-        UNKNOWN = 0;
-        ON_CONNECTED = 1;
-        ON_DISCONNECTED = 2;
-        SET_WHITELIST = 3;
-        SET_DISABLED = 4;
-        ON_USER_DATA_REMOVED = 5;
-        ON_DATA_SHARE_REQUEST = 6;
-        ACCEPT_DATA_SHARE_REQUEST = 7;
-        REJECT_DATA_SHARE_REQUEST = 8;
-        DATA_SHARE_WRITE_FINISHED = 9;
-        DATA_SHARE_ERROR_IOEXCEPTION = 10;
-        DATA_SHARE_ERROR_EMPTY_DATA = 11;
-        DATA_SHARE_ERROR_CLIENT_PIPE_FAIL = 12;
-        DATA_SHARE_ERROR_SERVICE_PIPE_FAIL = 13;
-        DATA_SHARE_ERROR_CONCURRENT_REQUEST = 14;
-        DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED = 15;
-    }
-    optional Event event = 1;
-    // component/package of content capture service.
-    optional string service_info = 2;
-    // component/package of target.
-    // it's a concatenated list of component/package for SET_WHITELIST event
-    // separated by " ".
-    optional string target_info = 3;
-}
-
-/**
- * Logs information about content capture session events.
- *
- * Logged from:
- *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
- */
-message ContentCaptureSessionEvents {
-    // The type of event.
-    enum Event {
-        UNKNOWN = 0;
-        ON_SESSION_STARTED = 1;
-        ON_SESSION_FINISHED = 2;
-        SESSION_NOT_CREATED = 3;
-    }
-    optional int32 session_id = 1;
-    optional Event event = 2;
-    // (n/a on session finished)
-    optional int32 state_flags = 3;
-    // component/package of content capture service.
-    optional string service_info = 4;
-    // component/package of app.
-    // (n/a on session finished)
-    optional string app_info = 5;
-    optional bool is_child_session = 6;
-}
-
-/**
- * Logs information about session being flushed.
- *
- * Logged from:
- *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
- */
-message ContentCaptureFlushed {
-    optional int32 session_id = 1;
-    // component/package of content capture service.
-    optional string service_info = 2;
-    // component/package of app.
-    optional string app_info = 3;
-    // session start/finish events
-    optional int32 child_session_started = 4;
-    optional int32 child_session_finished = 5;
-    // count of view events.
-    optional int32 view_appeared_count = 6;
-    optional int32 view_disappeared_count = 7;
-    optional int32 view_text_changed_count = 8;
-
-    // Flush stats.
-    optional int32 max_events = 9;
-    optional int32 idle_flush_freq = 10;
-    optional int32 text_flush_freq = 11;
-    optional int32 flush_reason = 12;
-}
-
-/**
- * Pulls on-device BatteryStats power use calculations for the overall device.
- */
-message DeviceCalculatedPowerUse {
-    // Power used by the device in nAs (i.e. nanocoulombs (nC)), as computed by BatteryStats, since
-    // BatteryStats last reset (i.e. roughly since device was last significantly charged).
-    // Currently, this is from BatteryStatsHelper.getComputedPower() (not getTotalPower()).
-    optional int64 computed_power_nano_amp_secs = 1;
-}
-
-/**
- * Pulls on-device BatteryStats power use calculations broken down by uid.
- * This atom should be complemented by DeviceCalculatedPowerBlameOther, which contains the power use
- * that is attributed to non-uid items. They must all be included to get the total power use.
- */
-message DeviceCalculatedPowerBlameUid {
-    // Uid being blamed. Note: isolated uids have already been mapped to host uid.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Power used by this uid in nAs (i.e. nanocoulombs (nC)), as computed by BatteryStats, since
-    // BatteryStats last reset (i.e. roughly since device was last significantly charged).
-    optional int64 power_nano_amp_secs = 2;
-}
-
-/**
- * Pulls on-device BatteryStats power use calculations that are not due to a uid, broken down by
- * drain type.
- * This atom should be complemented by DeviceCalculatedPowerBlameUid, which contains the blame that
- * is attributed uids. They must all be included to get the total power use.
- */
-message DeviceCalculatedPowerBlameOther {
-    // The type of item whose power use is being reported.
-    enum DrainType {
-        AMBIENT_DISPLAY = 0;
-        // reserved 1; reserved "APP"; // Logged instead in DeviceCalculatedPowerBlameUid.
-        BLUETOOTH = 2;
-        CAMERA = 3;
-        // Cell-standby
-        CELL = 4;
-        FLASHLIGHT = 5;
-        IDLE = 6;
-        MEMORY = 7;
-        // Amount that total computed drain exceeded the drain estimated using the
-        // battery level changes and capacity.
-        OVERCOUNTED = 8;
-        PHONE = 9;
-        SCREEN = 10;
-        // Amount that total computed drain was below the drain estimated using the
-        // battery level changes and capacity.
-        UNACCOUNTED = 11;
-        // reserved 12; reserved "USER"; // Entire drain for a user. This is NOT supported.
-        WIFI = 13;
-    }
-    optional DrainType drain_type = 1;
-
-    // Power used by this item in nAs (i.e. nanocoulombs (nC)), as computed by BatteryStats, since
-    // BatteryStats last reset (i.e. roughly since device was last significantly charged).
-    optional int64 power_nano_amp_secs = 2;
-}
-
-/**
- * Logs device policy features.
- *
- * Logged from:
- *   frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
- *   packages/apps/ManagedProvisioning/src/com/android/managedprovisioning/
- */
-message DevicePolicyEvent {
-    // The event id - unique for each event.
-    optional android.stats.devicepolicy.EventId event_id = 1;
-    // The admin package name.
-    optional string admin_package_name = 2;
-    // A generic integer parameter.
-    optional int32 integer_value = 3;
-    // A generic boolean parameter.
-    optional bool boolean_value = 4;
-    // A parameter specifying a time period in milliseconds.
-    optional uint64 time_period_millis = 5;
-    // A parameter specifying a list of package names, bundle extras or string parameters.
-    optional android.stats.devicepolicy.StringList string_list_value = 6 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUILaunchReported {
-    optional android.stats.docsui.LaunchAction launch_action = 1;
-    optional bool has_initial_uri = 2;
-    optional android.stats.docsui.MimeType mime_type = 3;
-    optional android.stats.docsui.Root initial_root = 4;
-}
-
-/**
- * Logs root/app visited event in file managers/picker. Call this when the user
- * taps on root/app in hamburger menu.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIRootVisitedReported {
-    optional android.stats.docsui.ContextScope scope = 1;
-    optional android.stats.docsui.Root root = 2;
-}
-
-/**
- * Logs file operation stats. Call this when a file operation has completed.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIFileOperationReported {
-    optional android.stats.docsui.Provider provider = 1;
-    optional android.stats.docsui.FileOperation file_op = 2;
-}
-
-/**
- * Logs file operation stats. Call this when a copy/move operation has completed with a specific
- * mode.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIFileOperationCopyMoveModeReported {
-    optional android.stats.docsui.FileOperation file_op = 1;
-    optional android.stats.docsui.CopyMoveOpMode mode = 2;
-}
-
-
-/**
- * Logs file sub operation stats. Call this when a file operation has failed.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIFileOperationFailureReported {
-    optional android.stats.docsui.Authority authority = 1;
-    optional android.stats.docsui.SubFileOperation sub_op = 2;
-}
-
-/**
-* Logs the cancellation of a file operation. Call this when a job is canceled
-*
-* Logged from:
-*     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
-*/
-message DocsUIFileOperationCanceledReported {
-    optional android.stats.docsui.FileOperation file_op = 1;
-}
-
-/**
- * Logs startup time in milliseconds.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIStartupMsReported {
-    optional int32 startup_millis = 1;
-}
-
-/**
- * Logs the action that was started by user.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIUserActionReported {
-    optional android.stats.docsui.UserAction action = 1;
-}
-
-/**
- * Logs the invalid type when invalid scoped access is requested.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/ScopedAccessMetrics.java
- */
-message DocsUIInvalidScopedAccessRequestReported {
-    optional android.stats.docsui.InvalidScopedAccess type = 1;
-}
-
-/**
- * Logs the package name that launches docsui picker mode.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIPickerLaunchedFromReported {
-    optional string package_name = 1;
-}
-
-/**
- * Logs the search type.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUISearchTypeReported {
-    optional android.stats.docsui.SearchType search_type = 1;
-}
-
-/**
- * Logs the search mode.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUISearchModeReported {
-    optional android.stats.docsui.SearchMode search_mode = 1;
-}
-
-/**
- * Logs the pick result information.
- *
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIPickResultReported {
-    optional int32 total_action_count = 1;
-    optional int64 duration_millis = 2;
-    optional int32 file_count= 3;
-    optional bool is_searching = 4;
-    optional android.stats.docsui.Root picked_from = 5;
-    optional android.stats.docsui.MimeType mime_type = 6;
-    optional int32 repeatedly_pick_times = 7;
-}
-
-/** Logs the drag and drop of files.
-
- * Logged from:
- *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
- */
-message DocsUIDragAndDropReported {
-    optional bool drag_initiated_from_docsui = 1;
-}
-
-/**
- * Logs when an app's memory is compacted.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message AppCompacted {
-  // The pid of the process being compacted.
-  optional int32 pid = 1;
-
-  // The name of the process being compacted.
-  optional string process_name = 2;
-
-  // The type of compaction.
-  enum Action {
-    UNKNOWN = 0;
-    SOME = 1;
-    FULL = 2;
-    PERSISTENT = 3;
-    BFGS = 4;
-  }
-  optional Action action = 3;
-
-  // Total RSS in kilobytes consumed by the process prior to compaction.
-  optional int64 before_rss_total_kilobytes = 4;
-
-  // File RSS in kilobytes consumed by the process prior to compaction.
-  optional int64 before_rss_file_kilobytes = 5;
-
-  // Anonymous RSS in kilobytes consumed by the process prior to compaction.
-  optional int64 before_rss_anon_kilobytes = 6;
-
-  // Swap in kilobytes consumed by the process prior to compaction.
-  optional int64 before_swap_kilobytes = 7;
-
-  // Total RSS in kilobytes consumed by the process after compaction.
-  optional int64 after_rss_total_kilobytes = 8;
-
-  // File RSS in kilobytes consumed by the process after compaction.
-  optional int64 after_rss_file_kilobytes = 9;
-
-  // Anonymous RSS in kilobytes consumed by the process after compaction.
-  optional int64 after_rss_anon_kilobytes = 10;
-
-  // Swap in kilobytes consumed by the process after compaction.
-  optional int64 after_swap_kilobytes = 11;
-
-  // The time taken to perform compaction in milliseconds.
-  optional int64 time_to_compact_millis = 12;
-
-  // The last compaction action performed for this app.
-  optional Action last_action = 13;
-
-  // The last time that compaction was attempted on this process in milliseconds
-  // since boot, not including sleep (see SystemClock.uptimeMillis()).
-  optional int64 last_compact_timestamp_ms_since_boot = 14;
-
-  // The "setAdj" (i.e. previous) oom_score_adj at the time of compaction.
-  optional int32 oom_score_adj = 15;
-
-  // The process state at the time of compaction.
-  optional android.app.ProcessStateEnum process_state = 16 [default = PROCESS_STATE_UNKNOWN];
-
-  // Free ZRAM in kilobytes before compaction.
-  optional int64 before_zram_free_kilobytes = 17;
-
-  // Free ZRAM in kilobytes after compaction.
-  optional int64 after_zram_free_kilobytes = 18;
-}
-
-/**
- * Logs when a Tethering event occurs.
- *
- */
-message NetworkTetheringReported {
-  // tethering error code
-  optional android.stats.connectivity.ErrorCode error_code = 1;
-
-  // tethering downstream type
-  optional android.stats.connectivity.DownstreamType downstream_type = 2;
-
-  // transport type of upstream network
-  optional android.stats.connectivity.UpstreamType upstream_type = 3;
-
-  // The user type of Tethering
-  optional android.stats.connectivity.UserType user_type= 4;
-}
-
-/**
- * Logs a DNS lookup operation initiated by the system resolver on behalf of an application
- * invoking native APIs such as getaddrinfo() or Java APIs such as Network#getAllByName().
- *
- * The NetworkDnsEventReported message represents the entire lookup operation, which may
- * result one or more queries to the recursive DNS resolvers. Those are individually logged
- * in DnsQueryEvents to enable computing error rates and network latency and timeouts
- * broken up by query type, transport, network interface, etc.
- */
-message NetworkDnsEventReported {
-    optional android.stats.dnsresolver.EventType event_type = 1;
-
-    optional android.stats.dnsresolver.ReturnCode return_code = 2;
-
-    // The latency in microseconds of the entire DNS lookup operation.
-    optional int32 latency_micros = 3;
-
-    // Only valid for event_type = EVENT_GETADDRINFO.
-    optional int32 hints_ai_flags = 4;
-
-    // Flags passed to android_res_nsend() defined in multinetwork.h
-    // Only valid for event_type = EVENT_RESNSEND.
-    optional int32 res_nsend_flags = 5;
-
-    optional android.stats.dnsresolver.NetworkType network_type = 6;
-
-    // The DNS over TLS mode on a specific netId.
-    optional android.stats.dnsresolver.PrivateDnsModes private_dns_modes = 7;
-
-    // Additional pass-through fields opaque to statsd.
-    // The DNS resolver Mainline module can add new fields here without requiring an OS update.
-    optional android.stats.dnsresolver.DnsQueryEvents dns_query_events = 8 [(log_mode) = MODE_BYTES];
-
-    // The sample rate of DNS stats (to statsd) is 1/sampling_rate_denom.
-    optional int32 sampling_rate_denom = 9;
-}
-
-/**
- * logs the CapportApiData info
- * Logged from:
- * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
- */
-message CapportApiData {
-    // The TTL of the network connection provided by captive portal
-    optional int32 remaining_ttl_secs = 1;
-
-    // The limit traffic data of the network connection provided by captive portal
-    optional int32 remaining_bytes = 2;
-
-    // Is portal url option included in the DHCP packet (Yes, No)
-    optional bool has_portal_url = 3;
-
-    // Is venue info (e.g. store info, maps, flight status) included (Yes, No)
-    optional bool has_venue_info = 4;
-}
-
-/**
- * logs a network Probe Event
- * Logged from:
- * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
- */
-message ProbeEvent {
-    // The probe type (http or https, or captive portal API...)
-    optional android.stats.connectivity.ProbeType probe_type = 1;
-
-    // The latency in microseconds of the probe event
-    optional int32 latency_micros = 2;
-
-    // The result of the probe event
-    optional android.stats.connectivity.ProbeResult probe_result = 3;
-
-    // The CaptivePortal API info
-    optional CapportApiData capport_api_data = 4;
-}
-
-/**
- * log each ProbeEvent in ProbeEvents
- * Logged from:
- * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
- */
-message ProbeEvents {
-    // Record probe event during the validation
-    repeated ProbeEvent probe_event = 1;
-}
-
-/**
- * The DHCP (Dynamic Host Configuration Protocol) session info
- * Logged from:
- * packages/modules/NetworkStack/src/android/net/dhcp/DhcpClient.java
- */
-message DhcpSession {
-    // The DHCP Feature(s) enabled in this session
-    repeated android.stats.connectivity.DhcpFeature used_features = 1;
-
-    // The discover packet (re)transmit count
-    optional int32 discover_count = 2;
-
-    // The request packet (re)transmit count
-    optional int32 request_count = 3;
-
-    // The IPv4 address conflict count
-    // (only be meaningful when duplicate address detection is enabled)
-    optional int32 conflict_count = 4;
-
-    // The DHCP packet parsing error code in this session
-    // (defined in android.net.metrics.DhcpErrorEvent)
-    repeated android.stats.connectivity.DhcpErrorCode error_code = 5;
-
-    // The result of DHCP hostname transliteration
-    optional android.stats.connectivity.HostnameTransResult ht_result = 6;
-}
-
-/**
- * Logs Network IP provisioning event
- * Logged from:
- * packages/modules/NetworkStack/src/com/android/networkstack/metrics/NetworkIpProvisioningMetrics.java
- */
-message NetworkIpProvisioningReported {
-    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
-    optional android.stats.connectivity.TransportType transport_type = 1;
-
-    // The latency in microseconds of IP Provisioning over IPV4
-    optional int32 ipv4_latency_micros = 2;
-
-    // The latency in microseconds of IP Provisioning over IPV6
-    optional int32 ipv6_latency_micros = 3;
-
-    // The time duration between provisioning start and end (success or failure)
-    optional int64 provisioning_duration_micros = 4;
-
-    // The specific disconnect reason for this IP provisioning
-    optional android.stats.connectivity.DisconnectCode disconnect_code = 5;
-
-    // Log DHCP session info (Only valid for IPv4)
-    optional DhcpSession dhcp_session = 6 [(log_mode) = MODE_BYTES];
-
-    // The random number between 0 ~ 999 for sampling
-    optional int32 random_number = 7;
-}
-
-/**
- * Logs Network DHCP Renew event
- * Logged from:
- * packages/modules/NetworkStack/src/android/net/dhcp/DhcpClient.java
- */
-message NetworkDhcpRenewReported {
-    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
-    optional android.stats.connectivity.TransportType transport_type = 1;
-
-    // The request packet (re)transmit count
-    optional int32 request_count = 2;
-
-    // The latency in microseconds of DHCP Renew
-    optional int32 latency_micros = 3;
-
-    // The DHCP error code is defined in android.net.metrics.DhcpErrorEvent
-    optional android.stats.connectivity.DhcpErrorCode error_code = 4;
-
-    // The result of DHCP renew
-    optional android.stats.connectivity.DhcpRenewResult renew_result = 5;
-
-    // The random number between 0 ~ 999 for sampling
-    optional int32 random_number = 6;
-}
-
-/**
- * Logs Network Validation event
- * Logged from:
- * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
- */
-message NetworkValidationReported {
-    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
-    optional android.stats.connectivity.TransportType transport_type = 1;
-
-    // Record each probe event
-    optional ProbeEvents probe_events = 2 [(log_mode) = MODE_BYTES];
-
-    // The result of the network validation
-    optional android.stats.connectivity.ValidationResult validation_result = 3;
-
-    // The latency in microseconds of network validation
-    optional int32 latency_micros = 4;
-
-    // The validation index (the first validation attempt or second, third...)
-    optional int32 validation_index = 5;
-
-    // The random number between 0 ~ 999 for sampling
-    optional int32 random_number = 6;
-}
-
-/**
- * Logs NetworkStack Quirk event
- * Logged from:
- * packages/modules/NetworkStack/src/com/android/networkstack/
- */
-message NetworkStackQuirkReported {
-    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
-    optional android.stats.connectivity.TransportType transport_type = 1;
-
-    // Record each Quirk event
-    optional android.stats.connectivity.NetworkQuirkEvent event = 2;
-}
-
-/**
- * Logs when a data stall event occurs.
- *
- * Log from:
- *     packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
- */
-message DataStallEvent {
-    // Data stall evaluation type.
-    // See packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
-    // Refer to the definition of DATA_STALL_EVALUATION_TYPE_*.
-    optional int32 evaluation_type = 1;
-    // See definition in data_stall_event.proto.
-    optional com.android.server.connectivity.ProbeResult validation_result = 2;
-    // See definition in data_stall_event.proto.
-    optional android.net.NetworkCapabilitiesProto.Transport network_type = 3;
-    // See definition in data_stall_event.proto.
-    optional com.android.server.connectivity.WifiData wifi_info = 4 [(log_mode) = MODE_BYTES];
-    // See definition in data_stall_event.proto.
-    optional com.android.server.connectivity.CellularData cell_info = 5 [(log_mode) = MODE_BYTES];
-    // See definition in data_stall_event.proto.
-    optional com.android.server.connectivity.DnsEvent dns_event = 6 [(log_mode) = MODE_BYTES];
-    // The tcp packets fail rate from the latest tcp polling.
-    optional int32 tcp_fail_rate = 7;
-    // Number of packets sent since the last received packet.
-    optional int32 tcp_sent_since_last_recv = 8;
-}
-
-/*
- * Logs when RescueParty resets some set of experiment flags.
- *
- * Logged from:
- *     frameworks/base/services/core/java/com/android/server/RescueParty.java
- */
-message RescuePartyResetReported {
-    // The rescue level of this reset. A value of 0 indicates missing or unknown level information.
-    optional int32 rescue_level = 1;
-}
-
-/**
- * Logs when signed config is received from an APK, and if that config was applied successfully.
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/signedconfig/SignedConfigService.java
- */
-message SignedConfigReported {
-    enum Type {
-        UNKNOWN_TYPE = 0;
-        GLOBAL_SETTINGS = 1;
-    }
-    optional Type type = 1;
-
-    // The final status of the signed config received.
-    enum Status {
-        UNKNOWN_STATUS = 0;
-        APPLIED = 1;
-        BASE64_FAILURE_CONFIG = 2;
-        BASE64_FAILURE_SIGNATURE = 3;
-        SECURITY_EXCEPTION = 4;
-        INVALID_CONFIG = 5;
-        OLD_CONFIG = 6;
-        SIGNATURE_CHECK_FAILED = 7;
-        NOT_APPLICABLE = 8;
-        SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT = 9;
-    }
-    optional Status status = 2;
-
-    // The version of the signed config processed.
-    optional int32 version = 3;
-
-    // The package name that the config was extracted from.
-    optional string from_package = 4;
-
-    enum Key {
-        NO_KEY = 0;
-        DEBUG = 1;
-        PRODUCTION = 2;
-    }
-    // Which key was used to verify the config.
-    optional Key verified_with = 5;
-}
-
-/*
- * Logs GNSS Network-Initiated (NI) location events.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
- */
-message GnssNiEventReported {
-    // The type of GnssNiEvent.
-    enum EventType {
-        UNKNOWN = 0;
-        NI_REQUEST = 1;
-        NI_RESPONSE = 2;
-    }
-    optional EventType event_type = 1;
-
-    // An ID generated by HAL to associate NI notifications and UI responses.
-    optional int32 notification_id = 2;
-
-    // A type which distinguishes different categories of NI request, such as VOICE, UMTS_SUPL etc.
-    optional android.server.location.GnssNiType ni_type = 3;
-
-    // NI requires notification.
-    optional bool need_notify = 4;
-
-    // NI requires verification.
-    optional bool need_verify = 5;
-
-    // NI requires privacy override, no notification/minimal trace.
-    optional bool privacy_override = 6;
-
-    // Timeout period to wait for user response. Set to 0 for no timeout limit. Specified in
-    // seconds.
-    optional int32 timeout = 7;
-
-    // Default response when timeout.
-    optional android.server.location.GnssUserResponseType default_response = 8;
-
-    // String representing the requester of the network inititated location request.
-    optional string requestor_id = 9;
-
-    // Notification message text string representing the service(for eg. SUPL-service) who sent the
-    // network initiated location request.
-    optional string text = 10;
-
-    // requestorId decoding scheme.
-    optional android.server.location.GnssNiEncodingType requestor_id_encoding = 11;
-
-    // Notification message text decoding scheme.
-    optional android.server.location.GnssNiEncodingType text_encoding = 12;
-
-    // True if SUPL ES is enabled.
-    optional bool is_supl_es_enabled = 13;
-
-    // True if GNSS location is enabled.
-    optional bool is_location_enabled = 14;
-
-    // GNSS NI responses which define the response in NI structures.
-    optional android.server.location.GnssUserResponseType user_response = 15;
-}
-
-/**
- * Logs GNSS non-framework (NFW) location notification.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
- */
-message GnssNfwNotificationReported {
-    // Package name of the Android proxy application representing the non-framework entity that
-    // requested location. Set to empty string if unknown.
-    optional string proxy_app_package_name = 1;
-
-    // Protocol stack that initiated the non-framework location request.
-    optional android.server.location.NfwProtocolStack protocol_stack = 2;
-
-    // Name of the protocol stack if protocol_stack field is set to OTHER_PROTOCOL_STACK. Otherwise,
-    // set to empty string. This field is opaque to the framework and used for logging purposes.
-    optional string other_protocol_stack_name = 3;
-
-    // Source initiating/receiving the location information.
-    optional android.server.location.NfwRequestor requestor = 4;
-
-    // Identity of the endpoint receiving the location information. For example, carrier name, OEM
-    // name, SUPL SLP/E-SLP FQDN, chipset vendor name, etc. This field is opaque to the framework
-    // and used for logging purposes.
-    optional string requestor_id = 5;
-
-    // Indicates whether location information was provided for this request.
-    optional android.server.location.NfwResponseType response_type = 6;
-
-    // True if the device is in user initiated emergency session.
-    optional bool in_emergency_mode = 7;
-
-    // True if cached location is provided.
-    optional bool is_cached_location = 8;
-
-    // True if proxy app permission mismatch between framework and GNSS HAL.
-    optional bool is_permission_mismatched = 9;
-}
-
-/**
- * Logs GNSS configuration as defined in IGnssConfiguration.hal.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/location/GnssConfiguration.java
- */
-message GnssConfigurationReported {
-    // SUPL host name.
-    optional string supl_host = 1;
-
-    // SUPL port number.
-    optional int32 supl_port = 2;
-
-    // C2K host name.
-    optional string c2k_host = 3;
-
-    // C2K port number.
-    optional int32 c2k_port = 4;
-
-    // The SUPL version requested by Carrier.
-    optional int32 supl_ver = 5;
-
-    // The SUPL mode.
-    optional android.server.location.SuplMode supl_mode = 6;
-
-    // True if NI emergency SUPL restrictions is enabled.
-    optional bool supl_es = 7;
-
-    // LTE Positioning Profile settings
-    optional android.server.location.LppProfile lpp_profile = 8;
-
-    // Positioning protocol on A-Glonass system.
-    optional android.server.location.GlonassPosProtocol a_glonass_pos_protocol_select = 9;
-
-    // True if emergency PDN is used. Otherwise, regular PDN is used.
-    optional bool use_emergency_pdn_for_emergency_supl= 10;
-
-    // Configurations of how GPS functionalities should be locked when user turns off GPS On setting.
-    optional android.server.location.GpsLock gps_lock = 11;
-
-    // Number of seconds to extend the emergency session duration post emergency call.
-    optional int32 es_extension_sec = 12;
-
-    // The full list of package names of proxy Android applications representing the non-framework
-    // location access entities (on/off the device) for which the framework user has granted
-    // non-framework location access permission. The package names are concatenated in one string
-    // with spaces as separators.
-    optional string enabled_proxy_app_package_name_list = 13;
-}
-
-/**
- * Logs when a NFC device's error occurred.
- * Logged from:
- *     system/nfc/src/nfc/nfc/nfc_ncif.cc
- *     packages/apps/Nfc/src/com/android/nfc/cardemulation/AidRoutingManager.java
- */
-message NfcErrorOccurred {
-    enum Type {
-        UNKNOWN = 0;
-        CMD_TIMEOUT = 1;
-        ERROR_NOTIFICATION = 2;
-        AID_OVERFLOW = 3;
-    }
-    optional Type type = 1;
-    // If it's nci cmd timeout, log the timeout command.
-    optional uint32 nci_cmd = 2;
-
-    optional uint32 error_ntf_status_code = 3;
-}
-
-/**
- * Logs when a NFC device's state changed event
- * Logged from:
- *     packages/apps/Nfc/src/com/android/nfc/NfcService.java
- */
-message NfcStateChanged {
-    enum State {
-        UNKNOWN = 0;
-        OFF = 1;
-        ON = 2;
-        ON_LOCKED = 3; // Secure Nfc enabled.
-        CRASH_RESTART = 4; // NfcService watchdog timeout restart.
-    }
-    optional State state = 1;
-}
-
-/**
- * Logs when a NFC Beam Transaction occurred.
- * Logged from:
- *     packages/apps/Nfc/src/com/android/nfc/P2pLinkManager.java
- */
-message NfcBeamOccurred {
-    enum Operation {
-        UNKNOWN = 0;
-        SEND = 1;
-        RECEIVE = 2;
-    }
-    optional Operation operation = 1;
-}
-
-/**
- * Logs when a NFC Card Emulation Transaction occurred.
- * Logged from:
- *     packages/apps/Nfc/src/com/android/nfc/cardemulation/HostEmulationManager.java
- *     packages/apps/Nfc/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java
- */
-message NfcCardemulationOccurred {
-    enum Category {
-        UNKNOWN = 0;
-        HCE_PAYMENT = 1;
-        HCE_OTHER = 2;
-        OFFHOST = 3;
-    }
-    // Transaction belongs to HCE payment or HCE other category, or offhost.
-    optional Category category = 1;
-    // SeName from transaction: SIMx, eSEx, HCE, HCEF.
-    optional string se_name = 2;
-}
-
-/**
- * Logs when a NFC Tag event occurred.
- * Logged from:
- *     packages/apps/Nfc/src/com/android/nfc/NfcDispatcher.java
- */
-message NfcTagOccurred {
-    enum Type {
-        UNKNOWN = 0;
-        URL = 1;
-        BT_PAIRING = 2;
-        PROVISION = 3;
-        WIFI_CONNECT = 4;
-        APP_LAUNCH = 5;
-        OTHERS = 6;
-    }
-    optional Type type = 1;
-}
-
-/**
- * Logs when Hce transaction triggered
- * Logged from:
- *     system/nfc/src/nfc/nfc/nfc_ncif.cc
- */
-message NfcHceTransactionOccurred {
-    // The latency period(in microseconds) it took for the first HCE data
-    // exchange.
-    optional uint32 latency_micros = 1;
-}
-
-/**
- * Logs when SecureElement state event changed
- * Logged from:
- *     packages/apps/SecureElement/src/com/android/se/Terminal.java
- */
-message SeStateChanged {
-    enum State {
-        UNKNOWN = 0;
-        INITIALIZED = 1;
-        DISCONNECTED = 2;
-        CONNECTED = 3;
-        HALCRASH = 4;
-    }
-    optional State state = 1;
-
-    optional string state_change_reason = 2;
-    // SIMx or eSEx.
-    optional string terminal = 3;
-}
-
-/**
- * Information about a permission grant request
- */
-message PermissionGrantRequestResultReported {
-    // unique value identifying an API call. A API call might result in multiple of these atoms
-    optional int64 request_id = 1;
-
-    // UID of package requesting the permission grant
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package requesting the permission grant
-    optional string package_name = 3;
-
-    // The permission to be granted
-    optional string permission_name = 4;
-
-    // If the permission was explicitly requested via the API or added by the system
-    optional bool is_implicit = 5;
-
-    enum Result {
-        UNDEFINED = 0;
-        // permission request was ignored
-        IGNORED = 1;
-        // permission request was ignored because it was user fixed
-        IGNORED_USER_FIXED = 2;
-        // permission request was ignored because it was policy fixed
-        IGNORED_POLICY_FIXED = 3;
-        // permission was granted by user action
-        USER_GRANTED = 4;
-        // permission was automatically granted
-        AUTO_GRANTED = 5;
-        // permission was denied by user action
-        USER_DENIED = 6;
-        // permission was denied with prejudice by the user
-        USER_DENIED_WITH_PREJUDICE = 7;
-        // permission was automatically denied
-        AUTO_DENIED = 8;
-        // permission request was ignored because permission is restricted
-        IGNORED_RESTRICTED_PERMISSION = 9;
-        // one time permission was granted by user action
-        USER_GRANTED_ONE_TIME = 10;
-        // user ignored request by leaving the request screen without choosing any option
-        USER_IGNORED = 11;
-        // user granted the permission after being linked to settings
-        USER_GRANTED_IN_SETTINGS = 12;
-        // user denied the permission after being linked to settings
-        USER_DENIED_IN_SETTINGS = 13;
-        // user denied the permission with prejudice after being linked to settings
-        USER_DENIED_WITH_PREJUDICE_IN_SETTINGS = 14;
-        // permission was automatically revoked after one-time permission expired
-        AUTO_ONE_TIME_PERMISSION_REVOKED = 15;
-        // permission was automatically revoked for unused app
-        AUTO_UNUSED_APP_PERMISSION_REVOKED = 16;
-    }
-    // The result of the permission grant
-    optional Result result = 6;
-}
-
-/**
- * Logs when Omapi API used
- * Logged from:
- *     packages/apps/SecureElement/src/com/android/se/Terminal.java
- */
-message SeOmapiReported {
-    enum Operation {
-        UNKNOWN = 0;
-        OPEN_CHANNEL = 1;
-    }
-    optional Operation operation = 1;
-    // SIMx or eSEx.
-    optional string terminal = 2;
-
-    optional string package_name = 3;
-}
-
-/**
-  * Logs the dispatch latency of a broadcast during processing of BOOT_COMPLETED.
-  * The dispatch latency is the dispatchClockTime - enqueueClockTime.
-  * Logged from:
-  *   frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
-  */
-message BroadcastDispatchLatencyReported {
-    optional int64 dispatch_latency_millis = 1;
-}
-
-/**
-   * Logs AttentionManagerService attention check result.
-   *
-   * Logged from:
-   *   frameworks/base/services/core/java/com/android/server/attention/AttentionManagerService.java
-   */
-message AttentionManagerServiceResultReported {
-    // See core/java/android/service/attention/AttentionService.java
-    enum AttentionCheckResult {
-        UNKNOWN = 20;
-        ATTENTION_SUCCESS_ABSENT = 0;
-        ATTENTION_SUCCESS_PRESENT = 1;
-        ATTENTION_FAILURE_UNKNOWN = 2;
-        ATTENTION_FAILURE_CANCELLED = 3;
-        ATTENTION_FAILURE_PREEMPTED = 4;
-        ATTENTION_FAILURE_TIMED_OUT = 5;
-        ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6;
-    }
-    optional AttentionCheckResult attention_check_result = 1 [default = UNKNOWN];
-}
-
-/**
- * Logs when an adb connection changes state.
- *
- * Logged from:
- *     frameworks/base/services/core/java/com/android/server/adb/AdbDebuggingManager.java
- */
-message AdbConnectionChanged {
-    // The last time this system connected via adb, or 0 if the 'always allow' option was not
-    // previously selected for this system.
-    optional int64 last_connection_time_millis = 1;
-
-    // The time in ms within which a subsequent connection from an 'always allow' system is allowed
-    // to reconnect via adb without user interaction.
-    optional int64 auth_window_millis = 2;
-
-    // The state of the adb connection from frameworks/base/core/proto/android/debug/enums.proto.
-    optional android.debug.AdbConnectionStateEnum state = 3;
-
-    // True if the 'always allow' option was selected for this system.
-    optional bool always_allow = 4;
-}
-
-/*
- * Logs the reported speech DSP status.
- *
- * Logged from:
- *  Vendor audio implementation.
- */
-message SpeechDspStatReported {
-    // The total Speech DSP uptime in milliseconds.
-    optional int32 total_uptime_millis = 1;
-    // The total Speech DSP downtime in milliseconds.
-    optional int32 total_downtime_millis = 2;
-    optional int32 total_crash_count = 3;
-    optional int32 total_recover_count = 4;
-}
-
-/**
- * Logs USB connector contaminant status.
- *
- * Logged from: USB Service.
- */
-message UsbContaminantReported {
-    optional string id = 1;
-    optional android.service.usb.ContaminantPresenceStatus status = 2;
-}
-
-/**
- * This atom is for debugging purpose.
- */
-message DebugElapsedClock {
-    // Monotically increasing value for each pull.
-    optional int64 pull_count = 1;
-    // Time from System.elapsedRealtime.
-    optional int64 elapsed_clock_millis = 2;
-    // Time from System.elapsedRealtime.
-    optional int64 same_elapsed_clock_millis = 3;
-    // Diff between current elapsed time and elapsed time from previous pull.
-    optional int64 elapsed_clock_diff_millis = 4;
-
-    enum Type {
-      TYPE_UNKNOWN = 0;
-      ALWAYS_PRESENT = 1;
-      PRESENT_ON_ODD_PULLS = 2;
-    }
-    // Type of behavior for the pulled data.
-    optional Type type = 5;
-}
-
-/**
- * This atom is for debugging purpose.
- */
-message DebugFailingElapsedClock {
-    // Monotically increasing value for each pull.
-    optional int64 pull_count = 1;
-    // Time from System.elapsedRealtime.
-    optional int64 elapsed_clock_millis = 2;
-    // Time from System.elapsedRealtime.
-    optional int64 same_elapsed_clock_millis = 3;
-    // Diff between current elapsed time and elapsed time from previous pull.
-    optional int64 elapsed_clock_diff_millis = 4;
-}
-
-/** Logs System UI bubbles event changed.
- *
- * Logged from:
- *     frameworks/base/packages/SystemUI/src/com/android/systemui/bubbles
- */
-message BubbleUIChanged {
-
-    // The app package that is posting the bubble.
-    optional string package_name = 1;
-
-    // The notification channel that is posting the bubble.
-    optional string notification_channel = 2;
-
-    // The notification id associated with the posted bubble.
-    optional int32 notification_id = 3;
-
-    // The position of the bubble within the bubble stack.
-    optional int32 position = 4;
-
-    // The total number of bubbles within the bubble stack.
-    optional int32 total_number = 5;
-
-    // User interactions with the bubble.
-    enum Action {
-        UNKNOWN = 0;
-        POSTED = 1;
-        UPDATED = 2;
-        EXPANDED = 3;
-        COLLAPSED = 4;
-        DISMISSED = 5;
-        STACK_DISMISSED = 6;
-        STACK_MOVED = 7;
-        HEADER_GO_TO_APP = 8;
-        HEADER_GO_TO_SETTINGS = 9;
-        PERMISSION_OPT_IN = 10;
-        PERMISSION_OPT_OUT = 11;
-        PERMISSION_DIALOG_SHOWN = 12;
-        SWIPE_LEFT = 13;
-        SWIPE_RIGHT = 14;
-        STACK_EXPANDED = 15;
-        FLYOUT = 16;
-    }
-    optional Action action = 6;
-
-    // Normalized screen position of the bubble stack. The range is between 0 and 1.
-    optional float normalized_x_position = 7;
-    optional float normalized_y_position = 8;
-
-    // Whether the bubble is unread. If it is unread, a dot is shown in the bubble stack icon.
-    optional bool is_unread = 9;
-
-    // Whether the bubble is an on-going one.
-    optional bool is_ongoing = 10;
-
-    // Whether the bubble is produced by an app running in foreground.
-    // This is deprecated and the value should be ignored.
-    optional bool is_foreground = 11 [deprecated = true];
-}
-
-/**
-  * Logs System UI bubbles developer errors.
-  *
-  * Logged from:
-  *   frameworks/base/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
-  */
-message BubbleDeveloperErrorReported {
-
-    // The app package that is posting the bubble.
-    optional string package_name = 1;
-
-    // Bubble developer error type enums.
-    enum Error {
-        UNKNOWN = 0;
-        ACTIVITY_INFO_MISSING = 1;
-        ACTIVITY_INFO_NOT_RESIZABLE = 2;
-        DOCUMENT_LAUNCH_NOT_ALWAYS = 3;
-    }
-    optional Error error = 2 [default = UNKNOWN];
-}
-
-/**
- * Logs that a constraint for a scheduled job has changed.
- *
- * Logged from:
- *     frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java
- */
-message ScheduledJobConstraintChanged {
-    repeated AttributionNode attribution_node = 1;
-
-    // Name of the job.
-    optional string job_name = 2;
-
-    optional com.android.server.job.ConstraintEnum constraint = 3;
-
-    enum State {
-        UNKNOWN = 0;
-        UNSATISFIED = 1;
-        SATISFIED = 2;
-    }
-    optional State state = 4;
-}
-
-/**
- * Logs PowerManagerService screen timeout resets (extensions) that happen when an attention check
- * returns true.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
- */
-message ScreenTimeoutExtensionReported {
-    // Describes how many times in a row did the power manager reset the screen off timeout.
-    optional uint32 consecutive_timeout_extended_count = 1;
-}
-
-/*
-* Logs number of milliseconds it takes to start a process.
-* The definition of app process start time is from the app launch time to
-* the time that Zygote finished forking the app process and loaded the
-* application package's java classes.
-
-* This metric is different from AppStartOccurred which is for foreground
-* activity only.
-
-* ProcessStartTime can report all processes (both foreground and background)
-* start time.
-*
-* Logged from:
-*   frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
-*/
-message ProcessStartTime {
-    // The uid of the ProcessRecord.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process pid.
-    optional int32 pid = 2;
-
-    // The process name.
-    // Usually package name, "system" for system server.
-    // Provided by ActivityManagerService.
-    optional string process_name = 3;
-
-    enum StartType {
-        UNKNOWN = 0;
-        WARM = 1;
-        HOT = 2;
-        COLD = 3;
-    }
-
-    // The start type.
-    optional StartType type = 4;
-
-    // The elapsed realtime at the start of the process.
-    optional int64 process_start_time_millis = 5;
-
-    // Number of milliseconds it takes to reach bind application.
-    optional int32 bind_application_delay_millis = 6;
-
-    // Number of milliseconds it takes to finish start of the process.
-    optional int32 process_start_delay_millis = 7;
-
-    // hostingType field in ProcessRecord, the component type such as "activity",
-    // "service", "content provider", "broadcast" or other strings.
-    optional string hosting_type = 8;
-
-    // hostingNameStr field in ProcessRecord. The component class name that runs
-    // in this process.
-    optional string hosting_name = 9;
-}
-
-/**
- * Track Media Codec usage
- * Logged from:
- *   frameworks/av/media/libstagefright/MediaCodec.cpp
- *   frameworks/av/services/mediaanalytics/statsd_codec.cpp
- */
-message MediametricsCodecReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.CodecData codec_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track Media Extractor (pulling video/audio streams out of containers) usage
- * Logged from:
- *   frameworks/av/media/libstagefright/RemoteMediaExtractor.cpp
- *   frameworks/av/services/mediaanalytics/statsd_extractor.cpp
- */
-message MediametricsExtractorReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.ExtractorData extractor_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track MediaParser (parsing video/audio streams from containers) usage
- * Logged from:
- *
- *   frameworks/av/services/mediametrics/statsd_mediaparser.cpp
- *   frameworks/base/apex/media/framework/jni/android_media_MediaParserJNI.cpp
- */
-message MediametricsMediaParserReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-
-    // MediaParser specific data.
-    /**
-     * The name of the parser selected for parsing the media, or an empty string
-     * if no parser was selected.
-     */
-    optional string parser_name = 4;
-    /**
-     * Whether the parser was created by name. 1 represents true, and 0
-     * represents false.
-     */
-    optional int32 created_by_name = 5;
-    /**
-     * The parser names in the sniffing pool separated by "|".
-     */
-    optional string parser_pool = 6;
-    /**
-     * The fully qualified name of the last encountered exception, or an empty
-     * string if no exception was encountered.
-     */
-    optional string last_exception = 7;
-    /**
-     * The size of the parsed media in bytes, or -1 if unknown. Note this value
-     * contains intentional random error to prevent media content
-     * identification.
-     */
-    optional int64 resource_byte_count = 8;
-    /**
-     * The duration of the media in milliseconds, or -1 if unknown. Note this
-     * value contains intentional random error to prevent media content
-     * identification.
-     */
-    optional int64 duration_millis = 9;
-    /**
-     * The MIME types of the tracks separated by "|".
-     */
-    optional string track_mime_types = 10;
-    /**
-     * The tracks' RFC 6381 codec strings separated by "|".
-     */
-    optional string track_codecs = 11;
-    /**
-     * Concatenation of the parameters altered by the client, separated by "|".
-     */
-    optional string altered_parameters = 12;
-    /**
-     * The video width in pixels, or -1 if unknown or not applicable.
-     */
-    optional int32 video_width = 13;
-    /**
-     * The video height in pixels, or -1 if unknown or not applicable.
-     */
-    optional int32 video_height = 14;
-}
-
-/**
- * Track how we arbitrate between microphone/input requests.
- * Logged from
- *   frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiopolicy.cpp
- */
-message MediametricsAudiopolicyReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.AudioPolicyData audiopolicy_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track how we arbitrate between microphone requests.
- * Logged from
- *   frameworks/av/media/libaudioclient/AudioRecord.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiorecord.cpp
- */
-message MediametricsAudiorecordReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.AudioRecordData audiorecord_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track how we arbitrate between microphone/input requests.
- * Logged from
- *   frameworks/av/media/libnblog/ReportPerformance.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiothread.cpp
- */
-message MediametricsAudiothreadReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.AudioThreadData audiothread_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track how we arbitrate between microphone/input requests.
- * Logged from
- *   frameworks/av/media/libaudioclient/AudioTrack.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiotrack.cpp
- */
-message MediametricsAudiotrackReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.AudioTrackData audiotrack_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track information about DRM framework performance
- * Logged from
- *   frameworks/av/drm/libmediadrm/DrmHal.cpp
- *   frameworks/av/services/mediaanalytics/statsd_drm.cpp
- */
-message MediametricsMediadrmReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    // vendor+description tell about which DRM plugin is in use on this device
-    optional string vendor = 5;
-    optional string description = 6;
-    // from frameworks/av/drm/libmediadrm/protos/metrics.proto
-    optional bytes framework_stats = 7 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track information about the widevine DRM plugin performance
- * Logged from
- *   vendor/widevine/libwvdrmengine/cdm/metrics
- *   frameworks/av/services/mediaanalytics/statsd_drm.cpp
- */
-message MediametricsDrmWidevineReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional bytes vendor_specific_stats = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track information about recordings (e.g. camcorder)
- * Logged from
- *   frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
- *   frameworks/av/services/mediaanalytics/statsd_recorder.cpp
- */
-message MediametricsRecorderReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.RecorderData recorder_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track Media Player usage
- * Logged from:
- *   frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
- *   frameworks/av/services/mediaanalytics/statsd_nuplayer.cpp
- */
-message MediametricsNuPlayerReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    optional android.stats.mediametrics.NuPlayerData nuplayer_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Track Legacy DRM usage
- * Logged from
- *   frameworks/av/drm/drmserver/DrmManager.cpp
- */
-message MediametricsDrmManagerReported {
-    optional int64 timestamp_nanos = 1;
-    optional string package_name = 2;
-    optional int64 package_version_code = 3;
-    optional int64 media_apex_version = 4;
-
-    enum Method {
-        METHOD_NOT_FOUND       = -1;
-        GET_CONSTRAINTS        =  0;
-        GET_METADATA           =  1;
-        CAN_HANDLE             =  2;
-        PROCESS_DRM_INFO       =  3;
-        ACQUIRE_DRM_INFO       =  4;
-        SAVE_RIGHTS            =  5;
-        GET_ORIGINAL_MIME_TYPE =  6;
-        GET_DRM_OBJECT_TYPE    =  7;
-        CHECK_RIGHTS_STATUS    =  8;
-        REMOVE_RIGHTS          =  9;
-        REMOVE_ALL_RIGHTS      = 10;
-        OPEN_CONVERT_SESSION   = 11;
-        OPEN_DECRYPT_SESSION   = 12;
-    }
-
-    // plugin_id+description inform which Legacy DRM plugins are still in use on device
-    optional string plugin_id = 5;
-    optional string description = 6;
-    optional Method method = 7;
-    optional string mime_types = 8;
-
-    optional int64 get_constraints_count =  9;
-    optional int64 get_metadata_count = 10;
-    optional int64 can_handle_count = 11;
-    optional int64 process_drm_info_count = 12;
-    optional int64 acquire_drm_info_count = 13;
-    optional int64 save_rights_count = 14;
-    optional int64 get_original_mime_type_count = 15;
-    optional int64 get_drm_object_type_count = 16;
-    optional int64 check_rights_status_count = 17;
-    optional int64 remove_rights_count = 18;
-    optional int64 remove_all_rights_count = 19;
-    optional int64 open_convert_session_count = 20;
-    optional int64 open_decrypt_session_count = 21;
-}
-
-/**
- * State of a dangerous permission requested by a package
- * Pulled from: StatsCompanionService
-*/
-message DangerousPermissionState {
-    // Name of the permission
-    optional string permission_name = 1;
-
-    // Uid of the package
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Package requesting the permission
-    optional string package_name = 3;
-
-    // If the permission is granted to the uid
-    optional bool is_granted = 4;
-
-    // Permission flags as per android.content.pm.PermissionFlags
-    optional int32 permission_flags = 5;
-}
-
-/**
- * Logs when a package is denied access to a device identifier based on the new access requirements.
- *
- * Logged from:
- *     frameworks/base/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
- */
-message DeviceIdentifierAccessDenied {
-    // The name of the package denied access to the requested device identifier.
-    optional string package_name = 1;
-
-    // The name of the device identifier method the package attempted to invoke.
-    optional string method_name = 2;
-
-    // True if the package is preinstalled.
-    // Starting from Android 11, this boolean is not set and will always be false.
-    optional bool is_preinstalled = 3 [deprecated = true];
-
-    // True if the package is privileged.
-    // Starting from Android 11, this boolean is not set and will always be false.
-    optional bool is_priv_app = 4 [deprecated = true];
-}
-
-/**
- * Pulls the ongoing mainline install train version code.
- * Pulled from StatsCompanionService
- */
-message TrainInfo {
-    optional int64 train_version_code = 1;
-
-    optional TrainExperimentIds train_experiment_id = 2 [(log_mode) = MODE_BYTES];
-
-    optional string train_name = 3;
-
-    enum Status {
-        UNKNOWN = 0;
-        INSTALL_REQUESTED = 1;
-        INSTALL_STARTED = 2;
-        INSTALL_STAGED_NOT_READY = 3;
-        INSTALL_STAGED_READY = 4;
-        INSTALL_SUCCESS = 5;
-        // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH,
-        // and INSTALL_FAILURE_COMMIT.
-        INSTALL_FAILURE = 6  [deprecated = true];
-        // This enum is for installs that are manually cancelled via the Manual Update UI.
-        INSTALL_CANCELLED = 7;
-        INSTALLER_ROLLBACK_REQUESTED = 8;
-        INSTALLER_ROLLBACK_INITIATED = 9;
-        INSTALLER_ROLLBACK_INITIATED_FAILURE = 10;
-        INSTALLER_ROLLBACK_STAGED = 11;
-        INSTALLER_ROLLBACK_STAGED_FAILURE = 12;
-        INSTALLER_ROLLBACK_BOOT_TRIGGERED = 13;
-        INSTALLER_ROLLBACK_BOOT_TRIGGERED_FAILURE = 14;
-        INSTALLER_ROLLBACK_SUCCESS = 15;
-        INSTALLER_ROLLBACK_FAILURE = 16;
-        INSTALLER_ROLLBACK_STAGED_CANCEL_REQUESTED = 17;
-        INSTALLER_ROLLBACK_STAGED_CANCEL_SUCCESS = 18;
-        INSTALLER_ROLLBACK_STAGED_CANCEL_FAILURE = 19;
-        INSTALL_STAGED_CANCEL_REQUESTED = 20;
-        INSTALL_STAGED_CANCEL_SUCCESS = 21;
-        INSTALL_STAGED_CANCEL_FAILURE = 22;
-        INSTALL_FAILURE_DOWNLOAD = 23;
-        INSTALL_FAILURE_STATE_MISMATCH = 24;
-        INSTALL_FAILURE_COMMIT = 25;
-        REBOOT_TRIGGERED = 26;
-    }
-    optional Status status = 4;
-}
-
-/**
- * Logs the gesture stage changed event.
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/
- */
-message AssistGestureStageReported {
-    optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
-}
-
-/**
- * Logs the feedback type.
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/
- */
-message AssistGestureFeedbackReported {
-    // Whether or not the gesture was used.
-    optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
-}
-
-/**
- * Logs the progress.
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/
- */
-message AssistGestureProgressReported {
-    // [0,100] progress for the assist gesture.
-    optional int32 progress = 1;
-}
-
-/*
- * Information about the time zone data on a device.
- */
-message TimeZoneDataInfo {
-    // A version identifier for the data set on device. e.g. "2018i"
-    optional string tzdb_version = 1;
-}
-
-/**
- * Logs the GPU stats global health information.
- *
- * Logged from:
- *   frameworks/native/services/gpuservice/gpustats/
- */
-message GpuStatsGlobalInfo {
-    // Package name of the gpu driver.
-    optional string driver_package_name = 1;
-
-    // Version name of the gpu driver.
-    optional string driver_version_name = 2;
-
-    // Version code of the gpu driver.
-    optional int64 driver_version_code = 3;
-
-    // Build time of the gpu driver in UTC as seconds since January 1, 1970.
-    optional int64 driver_build_time = 4;
-
-    // Total count of the gl driver gets loaded.
-    optional int64 gl_loading_count = 5;
-
-    // Total count of the gl driver fails to be loaded.
-    optional int64 gl_loading_failure_count = 6;
-
-    // Total count of the Vulkan driver gets loaded.
-    optional int64 vk_loading_count = 7;
-
-    // Total count of the Vulkan driver fails to be loaded.
-    optional int64 vk_loading_failure_count = 8;
-
-    // Api version of the system Vulkan driver.
-    optional int32 vulkan_version = 9;
-
-    // Api version of the system CPU Vulkan driver.
-    optional int32 cpu_vulkan_version = 10;
-
-    // Api version of the system GLES driver.
-    optional int32 gles_version = 11;
-
-    // Total count of the angle driver gets loaded.
-    optional int64 angle_loading_count = 12;
-
-    // Total count of the angle driver fails to be loaded.
-    optional int64 angle_loading_failure_count = 13;
-}
-
-/**
- * GPU driver loading time info.
- */
-message GpuDriverLoadingTime {
-    // List of all the driver loading times for this app. The list size is
-    // capped at 50.
-    repeated int64 driver_loading_time = 1;
-}
-
-/**
- * Logs the GPU stats per app health information.
- *
- * Logged from:
- *   frameworks/native/services/gpuservice/gpustats/
- */
-message GpuStatsAppInfo {
-    // Package name of the application that loads the gpu driver. Total number
-    // of different packages is capped at 100.
-    optional string app_package_name = 1;
-
-    // Version code of the gpu driver this app loads.
-    optional int64 driver_version_code = 2;
-
-    // gl driver loading time info.
-    optional GpuDriverLoadingTime gl_driver_loading_time = 3
-            [(android.os.statsd.log_mode) = MODE_BYTES];
-
-    // Vulkan driver loading time info.
-    optional GpuDriverLoadingTime vk_driver_loading_time = 4
-            [(android.os.statsd.log_mode) = MODE_BYTES];
-
-    // Angle driver loading time info.
-    optional GpuDriverLoadingTime angle_driver_loading_time = 5
-            [(android.os.statsd.log_mode) = MODE_BYTES];
-
-    // CPU Vulkan implementation is in use.
-    optional bool cpu_vulkan_in_use = 6;
-
-    // App is not doing pre-rotation correctly.
-    optional bool false_prerotation = 7;
-
-    // App creates GLESv1 context.
-    optional bool gles_1_in_use = 8;
-}
-
-/*
- * Logs the size of the system ion heap.
- *
- * Pulled from StatsCompanionService.
- */
-message SystemIonHeapSize {
-    // Deprecated due to limited support of ion stats in debugfs.
-    // Use `IonHeapSize` instead.
-    option deprecated = true;
-
-    // Size of the system ion heap in bytes.
-    // Read from debugfs.
-    optional int64 size_in_bytes = 1;
-}
-
-/*
- * Logs the total size of the ion heap.
- *
- * Pulled from StatsCompanionService.
- */
-message IonHeapSize {
-    // Total size of all ion heaps in kilobytes.
-    // Read from: /sys/kernel/ion/total_heaps_kb.
-    optional int32 total_size_kb = 1;
-}
-
-/*
- * Logs the per-process size of the system ion heap.
- *
- * Pulled from StatsCompanionService.
- */
-message ProcessSystemIonHeapSize {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name (from /proc/PID/cmdline).
-    optional string process_name = 2;
-
-    // Sum of sizes of all allocations.
-    optional int32 total_size_in_kilobytes = 3;
-
-    // Number of allocations.
-    optional int32 allocation_count = 4;
-
-    // Size of the largest allocation.
-    optional int32 max_size_in_kilobytes = 5;
-}
-
-/**
- * Push network stack events.
- *
- * Log from:
- *     frameworks/base/packages/NetworkStack/
- */
-message NetworkStackReported {
-    // The id that indicates the event reported from NetworkStack.
-    optional int32 event_id = 1;
-    // The data for the reported events.
-    optional android.stats.connectivity.NetworkStackEventData network_stack_event = 2 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs the apps that are installed on the external storage.
- * Pulled from:
- *   StatsCompanionService
- */
-message AppsOnExternalStorageInfo {
-    // The type of the external storage.
-    optional android.stats.storage.ExternalStorageType external_storage_type = 1;
-    // The name of the package that is installed on the external storage.
-    optional string package_name = 2;
-}
-
-/**
- * Logs the settings related to Face.
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/stats
- */
-message FaceSettings {
-    // Whether or not face unlock is allowed on Keyguard.
-    optional bool unlock_keyguard_enabled = 1;
-    // Whether or not face unlock dismisses the Keyguard.
-    optional bool unlock_dismisses_keyguard = 2;
-    // Whether or not face unlock requires attention.
-    optional bool unlock_attention_required = 3;
-    // Whether or not face unlock is allowed for apps (through BiometricPrompt).
-    optional bool unlock_app_enabled = 4;
-    // Whether or not face unlock always requires user confirmation.
-    optional bool unlock_always_require_confirmation = 5;
-    // Whether or not a diverse set of poses are required during enrollment.
-    optional bool unlock_diversity_required = 6;
-}
-
-/**
- * Logs cooling devices maintained by the kernel.
- *
- * Pulled from StatsCompanionService.java
- */
-message CoolingDevice {
-    // The type of cooling device being reported. Eg. CPU, GPU...
-    optional android.os.CoolingTypeEnum device_location = 1;
-    // The name of the cooling device source. Eg. CPU0
-    optional string device_name = 2;
-    // Current throttle state of the cooling device. The value can any unsigned
-    // integer between 0 and max_state defined in its driver. 0 means device is
-    // not in throttling, higher value means deeper throttling.
-    optional int32 state = 3;
-}
-
-/**
- * Intelligence has several counter-type events that don't warrant a
- * full separate atom. These are primarily API call counters but also include
- * counters for feature usage and specific failure modes.
- *
- * Logged from the Intelligence mainline module.
- */
-message IntelligenceEventReported {
-  // The event type.
-  optional android.stats.intelligence.EventType event_id = 1;
-  // Success, failure.
-  optional android.stats.intelligence.Status status = 2;
-  // How many times the event occured (to report a batch of high frequency events).
-  optional int32 count = 3;
-  // How long the event took (sum of durations if count > 1)
-  optional int64 duration_millis = 4;
-}
-
-/**
- * Logs when Car Power state changed.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/CarStatsLog.java
- */
-message CarPowerStateChanged {
-    // States come from CpmsState in CarPowerManagementService.java.
-    enum State {
-       WAIT_FOR_VHAL = 0;
-       ON = 1;
-       SHUTDOWN_PREPARE = 2;
-       WAIT_FOR_FINISH = 3;
-       SUSPEND = 4;
-       SIMULATE_SLEEP = 5;
-    }
-    optional State state = 1;
-}
-
-/**
- * Logs when Car User Hal is requested to switch/create/remove user.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
- */
-message CarUserHalModifyUserRequestReported {
-    // Request id for the request.
-    optional int32 request_id = 1;
-    // Request type.
-    enum RequestType {
-        UNKNOWN = 0;
-        // Car user manager requested user switch.
-        SWITCH_REQUEST_ANDROID = 1;
-        // OEM requested User switch.
-        SWITCH_REQUEST_OEM = 2;
-        // Hal switch requested after android switch using activity manager.
-        SWITCH_REQUEST_LEGACY = 3;
-        // Create User
-        CREATE_REQUEST = 4;
-        // Remove User
-        REMOVE_REQUEST = 5;
-    }
-    optional RequestType request_type = 2;
-    // Android User id of the current user which can only be 0, 10, 11 and so on.
-    // -1 if not available.
-    optional int32 user_id = 3;
-    // VHAL flags of the current user. (-1 if not available)
-    optional int32 user_flags = 4;
-    // Android User id of the target user for switch/create/remove. It can only
-    // be 0, 10, 11 and so on. -1 if not available.
-    optional int32 target_user_id = 5;
-    // VHAL flags of the target user for switch/create/remove. (-1 if not available)
-    optional int32 target_user_flags = 6;
-    // Request timeout Milliseconds (-1 if not available)
-    optional int32 timeout_millis = 7;
-}
-
-/**
- * Logs when Car User Hal responds to switch/create user request.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
- */
-message CarUserHalModifyUserResponseReported {
-    // Request id of the request associated with the response.
-    optional int32 request_id = 1;
-    // Car user hal callback status.
-    enum CallbackStatus {
-        UNKNOWN = 0;
-        // Hal response was invalid.
-        INVALID = 1;
-        // Hal response was ok.
-        OK = 2;
-        // Hal timeout during set call.
-        HAL_SET_TIMEOUT = 3;
-        // Hal response timeout.
-        HAL_RESPONSE_TIMEOUT = 4;
-        // Hal responded with wrong info.
-        WRONG_HAL_RESPONSE = 5;
-        // Hal is processing multiple requests simultaneously.
-        CONCURRENT_OPERATION = 6;
-    }
-    optional CallbackStatus callback_status = 2;
-
-    // Hal request status for user switch/create/remove.
-    enum HalRequestStatus {
-        UNSPECIFIED = 0;
-        // Hal request for user switch/create is successful.
-        SUCCESS = 1;
-        // Hal request for user switch/create failed.
-        FAILURE = 2;
-    }
-    optional HalRequestStatus request_status = 3;
-}
-
-/**
- * Logs when post switch response is posted to Car User Hal.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
- */
-message CarUserHalPostSwitchResponseReported {
-    // Request id.
-    optional int32 request_id = 1;
-
-    // Android user switch status.
-    enum UserSwitchStatus {
-        UNKNOWN = 0;
-        // Android user switch is successful.
-        SUCCESS = 1;
-        // Android user switch failed.
-        FAILURE = 2;
-    }
-    optional UserSwitchStatus switch_status = 2;
-}
-
-/**
- * Logs when initial user information is requested from Car User Hal.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
- */
-message CarUserHalInitialUserInfoRequestReported {
-    // Request id for the request.
-    optional int32 request_id = 1;
-
-    // Request type for initial user information.
-    enum InitialUserInfoRequestType {
-        UNKNOWN = 0;
-        // At the first time Android was booted (or after a factory reset).
-        FIRST_BOOT = 1;
-        // At the first time Android was booted after the system was updated.
-        FIRST_BOOT_AFTER_OTA = 2;
-        // When Android was booted "from scratch".
-        COLD_BOOT = 3;
-        // When Android was resumed after the system was suspended to memory.
-        RESUME = 4;
-    }
-    optional InitialUserInfoRequestType request_type = 2;
-    // Request timeout Milliseconds (-1 if not available)
-    optional int32 timeout_millis = 3;
-}
-
-/**
- * Logs when Car User Hal responds to initial user information requests.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
- */
-message CarUserHalInitialUserInfoResponseReported {
-    // Request id of the request associated with the response.
-    optional int32 request_id = 1;
-    // Car user hal callback status.
-    enum CallbackStatus {
-        UNKNOWN = 0;
-        // Hal response was invalid.
-        INVALID = 1;
-        // Hal response was ok.
-        OK = 2;
-        // Hal timeout during set call.
-        HAL_SET_TIMEOUT = 3;
-        // Hal response timeout.
-        HAL_RESPONSE_TIMEOUT = 4;
-        // Hal responded with wrong info.
-        WRONG_HAL_RESPONSE = 5;
-        // Hal is processing multiple requests simultaneously.
-        CONCURRENT_OPERATION = 6;
-    }
-    optional CallbackStatus callback_status = 2;
-    // Response for initial user information request.
-    enum InitialUserInfoResponseAction {
-        UNSPECIFIED = 0;
-        // Let the Android System decide what to do.
-        DEFAULT = 1;
-        // Switch to an existing Android user.
-        SWITCH = 2;
-        // Create a new Android user (and switch to it).
-        CREATE = 3;
-    }
-    optional InitialUserInfoResponseAction response_action = 3;
-    // Android User id of the target user which can only be 0, 10, 11 and so on.
-    // -1 if not available.
-    optional int32 target_user = 4;
-    // VHAL flags of the current user. (-1 if not available)
-    optional int32 target_user_flags = 5;
-    // User locales
-    optional string user_locales = 6;
-}
-
-/**
- * Logs when set user association is requested from Car User Hal.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
- */
-message CarUserHalUserAssociationRequestReported {
-    // Request id for the request.
-    optional int32 request_id = 1;
-    // Request type.
-    enum RequestType {
-        UNKNOWN = 0;
-        // For setting user association information.
-        SET = 1;
-        // For getting user association information.
-        GET = 2;
-    }
-    optional RequestType request_type = 2;
-    // Android User id of the current user which can only be 0, 10, 11 and so on.
-    // -1 if not available.
-    optional int32 current_user_id = 3;
-    // VHAL flags of the current user. (-1 if not available)
-    optional int32 current_user_flags = 4;
-    // Number of the set associations requested.
-    optional int32 number_associations = 5;
-    // Concatenated string for the types from set associations request.
-    // This is a string converted from an array of integers.
-    optional string user_identification_association_types = 6;
-    // Concatenated string for the values from set associations request.
-    // This is a string converted from an array of integers.
-    optional string user_identification_association_values = 7;
-}
-
-/**
- * Logs when Car User Hal responds to set user association requests.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
- */
-message CarUserHalSetUserAssociationResponseReported {
-    // Request id of the request associated with the response.
-    optional int32 request_id = 1;
-    // Car user hal callback status.
-    enum CallbackStatus {
-        UNKNOWN = 0;
-        // Hal response was invalid.
-        INVALID = 1;
-        // Hal response was ok.
-        OK = 2;
-        // Hal timeout during set call.
-        HAL_SET_TIMEOUT = 3;
-        // Hal response timeout.
-        HAL_RESPONSE_TIMEOUT = 4;
-        // Hal responded with wrong info.
-        WRONG_HAL_RESPONSE = 5;
-        // Hal is processing multiple requests simultaneously.
-        CONCURRENT_OPERATION = 6;
-    }
-    optional CallbackStatus callback_status = 2;
-    // Number of the set associations in the response.
-    optional int32 number_associations = 3;
-    // Concatenated string for the types from set associations request.
-    // This is a string converted from an array of integers.
-    optional string user_identification_association_types = 4;
-    // Concatenated string for the values from set associations request.
-    // This is a string converted from an array of integers.
-    optional string user_identification_association_values = 5;
-}
-
-/**
- * Logs whether GarageMode is entered.
- *
- * Logged from:
- *   packages/services/Car/service/src/com/android/car/CarStatsLog.java
- */
-message GarageModeInfo {
-    // Whether GarageMode is entered.
-    optional bool is_garage_mode = 1;
-}
-
-/**
- * Historical app ops data per package.
- */
-message AppOps {
-    // Uid of the package requesting the op
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Name of the package performing the op
-    optional string package_name = 2;
-
-    // operation id
-    optional android.app.AppOpEnum op_id = 3 [default = APP_OP_NONE];
-
-    // The number of times the op was granted while the app was in the
-    // foreground (only for trusted requests)
-    optional int64 trusted_foreground_granted_count = 4;
-
-    // The number of times the op was granted while the app was in the
-    // background (only for trusted requests)
-    optional int64 trusted_background_granted_count = 5;
-
-    // The number of times the op was rejected while the app was in the
-    // foreground (only for trusted requests)
-    optional int64 trusted_foreground_rejected_count = 6;
-
-    // The number of times the op was rejected while the app was in the
-    // background (only for trusted requests)
-    optional int64 trusted_background_rejected_count = 7;
-
-    // For long-running operations, total duration of the operation
-    // while the app was in the foreground (only for trusted requests)
-    optional int64 trusted_foreground_duration_millis = 8;
-
-    // For long-running operations, total duration of the operation
-    // while the app was in the background (only for trusted requests)
-    optional int64 trusted_background_duration_millis = 9;
-
-    // Whether AppOps is guarded by Runtime permission
-    optional bool is_runtime_permission = 10;
-}
-
-/**
- * Historical app ops data per package and attribution tag.
- */
-message AttributedAppOps {
-    // Uid of the package requesting the op
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Name of the package performing the op
-    optional string package_name = 2;
-
-    // tag; provided by developer when accessing related API, limited at 50 chars by API.
-    // Attributions must be provided through manifest using <attribution> tag available in R and
-    // above.
-    optional string tag = 3;
-
-    // operation id
-    optional android.app.AppOpEnum op = 4 [default = APP_OP_NONE];
-
-    // The number of times the op was granted while the app was in the
-    // foreground (only for trusted requests)
-    optional int64 trusted_foreground_granted_count = 5;
-
-    // The number of times the op was granted while the app was in the
-    // background (only for trusted requests)
-    optional int64 trusted_background_granted_count = 6;
-
-    // The number of times the op was rejected while the app was in the
-    // foreground (only for trusted requests)
-    optional int64 trusted_foreground_rejected_count = 7;
-
-    // The number of times the op was rejected while the app was in the
-    // background (only for trusted requests)
-    optional int64 trusted_background_rejected_count = 8;
-
-    // For long-running operations, total duration of the operation
-    // while the app was in the foreground (only for trusted requests)
-    optional int64 trusted_foreground_duration_millis = 9;
-
-    // For long-running operations, total duration of the operation
-    // while the app was in the background (only for trusted requests)
-    optional int64 trusted_background_duration_millis = 10;
-
-    // Whether AppOps is guarded by Runtime permission
-    optional bool is_runtime_permission = 11;
-
-    // Sampling rate used on device, from 0 to 100
-    optional int32 sampling_rate = 12;
-}
-
-/**
- * Location Manager API Usage information(e.g. API under usage,
- * API call's parameters).
- * Logged from:
- *  frameworks/base/services/core/java/com/android/server/LocationManagerService.java
- */
-message LocationManagerApiUsageReported {
-
-    // Indicating if usage starts or usage ends.
-    optional android.stats.location.UsageState state = 1;
-
-    // LocationManagerService's API in use.
-    // We can identify which API from LocationManager is
-    // invoking current LMS API by the combination of
-    // API parameter(e.g. is_listener_null, is_intent_null,
-    // is_location_request_null)
-    optional android.stats.location.LocationManagerServiceApi api_in_use = 2;
-
-    // Name of the package calling the API.
-    optional string calling_package_name = 3;
-
-    // Type of the location provider.
-    optional android.stats.location.ProviderType provider = 4;
-
-    // Quality of the location request
-    optional android.stats.location.LocationRequestQuality quality = 5;
-
-    // The desired interval for active location updates, in milliseconds.
-    // Bucketized to reduce cardinality.
-    optional android.stats.location.LocationRequestIntervalBucket bucketized_interval = 6;
-
-    // Minimum distance between location updates, in meters.
-    // Bucketized to reduce cardinality.
-    optional android.stats.location.SmallestDisplacementBucket
-            bucketized_smallest_displacement = 7;
-
-    // The number of location updates.
-    optional int64 num_updates = 8;
-
-    // The request expiration time, in millisecond since boot.
-    // Bucketized to reduce cardinality.
-    optional android.stats.location.ExpirationBucket
-            bucketized_expire_in = 9;
-
-    // Type of Callback passed in for this API.
-    optional android.stats.location.CallbackType callback_type = 10;
-
-    // The radius of the central point of the alert
-    // region, in meters. Only for API REQUEST_GEOFENCE.
-    // Bucketized to reduce cardinality.
-    optional android.stats.location.GeofenceRadiusBucket bucketized_radius = 11;
-
-    // Activity Importance of API caller.
-    // Categorized to 3 types that are interesting from location's perspective.
-    optional android.stats.location.ActivityImportance activiy_importance = 12;
-}
-
-/**
- * Information about a permission grant or denial made by user inside ReviewPermissionsFragment
- */
-message ReviewPermissionsFragmentResultReported {
-    // unique value identifying a permission group change. A permission group change might result
-    // in multiple of these atoms
-    optional int64 change_id = 1;
-
-    // UID of package the permission belongs to
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package the permission belongs to
-    optional string package_name = 3;
-
-    // The permission to be granted
-    optional string permission_name = 4;
-
-    // The result of the permission grant
-    optional bool permission_granted = 5;
-}
-
-/**
-* Information about results of permission upgrade by RuntimePermissionsUpgradeController
-* Logged from: RuntimePermissionUpdgradeController
-*/
-message RuntimePermissionsUpgradeResult {
-    // Permission granted as result of upgrade
-    optional string permission_name = 1;
-
-    // UID of package granted permission
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package granted permission
-    optional string package_name = 3;
-}
-
-/**
-* Information about a buttons presented in GrantPermissionsActivty and choice made by user
-*/
-message GrantPermissionsActivityButtonActions {
-    // Permission granted as result of upgrade
-    optional string permission_group_name = 1;
-
-    // UID of package granted permission
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package requesting permission
-    optional string package_name = 3;
-
-    // Buttons presented in the dialog - bit flags, bit numbers are in accordance with
-    // LABEL_ constants in GrantPermissionActivity.java
-    optional int32 buttons_presented = 4;
-
-    // Button clicked by user - same as bit flags in buttons_presented with only single bit set
-    optional int32 button_clicked = 5;
-
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 6;
-}
-
-/**
- * Information about LocationAccessCheck notification presented to user
- */
-message LocationAccessCheckNotificationAction {
-
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // Uid of package for which location access check is presented
-    optional int32 package_uid = 2;
-
-    // Name of package for which location access check is presented
-    optional string package_name = 3;
-
-    enum Result {
-        UNDEFINED = 0;
-        // notification was presented to the user
-        NOTIFICATION_PRESENTED = 1;
-        // notification was declined by the user
-        NOTIFICATION_DECLINED = 2;
-        // notification was clicked by the user
-        NOTIFICATION_CLICKED = 3;
-    }
-
-    // View / interaction recorded
-    optional Result result = 4;
-}
-
-/**
- * Information about a permission grant or revoke made by user inside AppPermissionFragment
- */
-message AppPermissionFragmentActionReported {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // unique value identifying a permission group change. A permission group change might result
-    // in multiple of these atoms
-    optional int64 change_id = 2;
-
-    // UID of package the permission belongs to
-    optional int32 uid = 3 [(is_uid) = true];
-
-    // Name of package the permission belongs to
-    optional string package_name = 4;
-
-    // The permission to be granted
-    optional string permission_name = 5;
-
-    // The result of the permission grant
-    optional bool permission_granted = 6;
-
-    // State of Permission Flags after grant as per android.content.pm.PermissionFlags
-    optional int32 permission_flags = 7;
-
-    enum Button {
-        UNDEFINED = 0;
-        // Allow button
-        ALLOW = 1;
-        // Deny button
-        DENY = 2;
-        // Ask every time button
-        ASK_EVERY_TIME = 3;
-        // Allow all the time button
-        ALLOW_ALWAYS = 4;
-        // Allow only while using the app button
-        ALLOW_FOREGROUND = 5;
-        // Same is Deny button but shown in while in use dialog
-        DENY_FOREGROUND = 6;
-    }
-
-    // Button pressed in the dialog
-    optional Button button_pressed = 8;
-}
-
-/**
-* Information about a AppPermissionFragment viewed by user
-*/
-message AppPermissionFragmentViewed {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // UID of package for which permissions are viewed
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package for which permissions are viewed
-    optional string package_name = 3;
-
-    // Permission group viewed
-    optional string permission_group_name = 4;
-}
-
-/**
-* Information about a AppPermissionGroupsFragment viewed by user. Fragment has been renamed, but
-* the log retains the old fragment name.
-*/
-message AppPermissionsFragmentViewed {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // id which identifies single view as every view might have several logging records
-    // with different package information attached
-    optional int64 view_id = 2;
-
-    // Permission group viewed
-    optional string permission_group_name = 3;
-
-    // UID of package for which permissions are viewed
-    optional int32 uid = 4 [(is_uid) = true];
-
-    // Name of package for which permissions are viewed
-    optional string package_name = 5;
-
-    // Category in which permission is included
-    enum Category {
-      UNDEFINED = 0;
-      ALLOWED = 1;
-      ALLOWED_FOREGROUND = 2;
-      DENIED = 3;
-    }
-    optional Category category = 6;
-}
-/**
-* Information about a PermissionAppsFragment viewed by user.
-* Logged from ui/handheld/PermissionAppsFragment.java
-*/
-message PermissionAppsFragmentViewed {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // id which identifies single view as every view might have several logging records
-    // with different package information attached
-    optional int64 view_id = 2;
-
-    // Permission group viewed
-    optional string permission_group_name = 3;
-
-    // UID of package for which permissions are viewed
-    optional int32 uid = 4 [(is_uid) = true];
-
-    // Name of package for which permissions are viewed
-    optional string package_name = 5;
-
-    // Category in which app is included
-    enum Category {
-        UNDEFINED = 0;
-        ALLOWED = 1;
-        ALLOWED_FOREGROUND = 2;
-        DENIED = 3;
-    }
-    optional Category category = 6;
-}
-
-/**
-* Log that the Auto Revoke notification has been clicked
-* Logged from ui/ManagePermissionsActivity
-*/
-message AutoRevokeNotificationClicked {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-}
-
-/**
-* Log that an app has been displayed on the auto revoke page, and lists one permission that was
-* auto revoked for it.
-* Logged from ui/handheld/AutoRevokeFragment
-*/
-message AutoRevokeFragmentAppViewed {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // UID of package for which permissions are viewed
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package for which permissions are viewed
-    optional string package_name = 3;
-
-    // The name of a permission group that has been revoked
-    optional string permission_group_name = 4;
-
-    // The age of the app- more than three months old, or more than six months
-    enum Age {
-        UNDEFINED = 0;
-        NEWER_BUCKET = 1;
-        OLDER_BUCKET = 2;
-    }
-
-    // How long the app has been unused. Currently, newer bucket is 3 months, older is 6 months
-    optional Age age = 5;
-}
-
-/**
-* Log that the user has interacted with an app on the auto revoke fragment
-* Logged from ui/handheld/AutoRevokeFragment
-*/
-message AutoRevokedAppInteraction {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // UID of package for which permissions are viewed
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package for which permissions are viewed
-    optional string package_name = 3;
-
-    enum Action {
-        UNDEFINED = 0;
-        REMOVE = 1;
-        OPEN = 2;
-        APP_INFO = 3;
-        PERMISSIONS = 4;
-        REMOVE_IN_SETTINGS = 5;
-        OPEN_IN_SETTINGS = 6;
-    }
-
-    // The action the user took to interact with the app
-    optional Action action = 4;
-}
-
-/**
-* Log that the AppPermissionGroupsFragment has been interacted with for the possible purposes of
-* auto revoke, or that the auto revoke switch has been changed
-* Logged from ui/handheld/AppPermissionGroupsFragment
- */
-message AppPermissionGroupsFragmentAutoRevokeAction {
-    // id which identifies single session of user interacting with permission controller
-    optional int64 session_id = 1;
-
-    // UID of package for which permissions are viewed
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // Name of package for which permissions are viewed
-    optional string package_name = 3;
-
-    enum Action {
-        UNDEFINED = 0;
-        OPENED_FOR_AUTO_REVOKE = 1;
-        OPENED_FROM_INTENT = 2;
-        SWITCH_ENABLED = 3;
-        SWITCH_DISABLED = 4;
-    }
-
-    // The action the user took to interact with the fragment
-    optional Action action = 4;
-}
-
-/**
- * Logs when there is a smart selection related event.
- * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
- * Logged from: TextClassifierEventLogger.java
- */
-message TextSelectionEvent {
-    // A session ID.
-    optional string session_id = 1;
-
-    // Event type of this event.
-    optional android.stats.textclassifier.EventType event_type = 2;
-
-    // Name of the annotator model that is involved in this event.
-    optional string model_name = 3;
-
-    // Type of widget that was involved in triggering this event.
-    optional android.stats.textclassifier.WidgetType widget_type = 4;
-
-    // Index of this event in a session.
-    optional int32 event_index = 5;
-
-    // Entity type that is involved.
-    optional string entity_type = 6;
-
-    // Relative word index of the start of the selection.
-    optional int32 relative_word_start_index = 7;
-
-    // Relative word (exclusive) index of the end of the selection.
-    optional int32 relative_word_end_index = 8;
-
-    // Relative word index of the start of the smart selection.
-    optional int32 relative_suggested_word_start_index = 9;
-
-    // Relative word (exclusive) index of the end of the smart selection.
-    optional int32 relative_suggested_word_end_index = 10;
-
-    // Name of source package.
-    optional string package_name = 11;
-
-    // Name of the LangID model that is involved in this event.
-    optional string langid_model_name = 12;
-}
-
-/**
- * Logs when there is a smart linkify related event.
- * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
- * Logged from: TextClassifierEventLogger.java
- */
-message TextLinkifyEvent {
-    // A session ID.
-    optional string session_id = 1;
-
-    // Event type of this event.
-    optional android.stats.textclassifier.EventType event_type = 2;
-
-    // Name of the annotator model that is involved in this event.
-    optional string model_name = 3;
-
-    // Type of widget that was involved in triggering this event.
-    optional android.stats.textclassifier.WidgetType widget_type = 4;
-
-    // Index of this event in a session.
-    optional int32 event_index = 5;
-
-    // Entity type that is involved.
-    optional string entity_type = 6;
-
-    // Number of links detected.
-    optional int32 num_links = 7;
-
-    // The total length of all links.
-    optional int32 linked_text_length = 8;
-
-    // Length of input text.
-    optional int32 text_length = 9;
-
-    // Time spent on generating links in ms.
-    optional int64 latency_millis = 10;
-
-    // Name of source package.
-    optional string package_name = 11;
-
-    // Name of the LangID model that is involved in this event.
-    optional string langid_model_name = 12;
-}
-
-/**
- * Logs when there is a conversation actions related event.
- * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
- * Logged from: TextClassifierEventLogger.java
- */
-message ConversationActionsEvent {
-    // A session ID.
-    optional string session_id = 1;
-
-    // Event type of this event.
-    optional android.stats.textclassifier.EventType event_type = 2;
-
-    // Name of the actions model that is involved in this event.
-    optional string model_name = 3;
-
-    // Type of widget that was involved in triggering this event.
-    optional android.stats.textclassifier.WidgetType widget_type = 4;
-
-    // The first entity type that is involved.
-    optional string first_entity_type = 5;
-
-    // The second entity type that is involved.
-    optional string second_entity_type = 6;
-
-    // The third entity type that is involved.
-    optional string third_entity_type = 7;
-
-    // The score of the first entity type.
-    optional float score = 8;
-
-    // Name of source package.
-    optional string package_name = 9;
-
-    // Name of the annotator model that is involved in this event.
-    optional string annotator_model_name = 10;
-
-    // Name of the LangID model that is involved in this event.
-    optional string langid_model_name = 11;
-}
-
-/**
- * Logs when there is a language detection related event.
- * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
- * Logged from: TextClassifierEventLogger.java
- */
-message LanguageDetectionEvent {
-    // A session ID.
-    optional string session_id = 1;
-
-    // Event type of this event.
-    optional android.stats.textclassifier.EventType event_type = 2;
-
-    // Name of the language detection model that is involved in this event.
-    optional string model_name = 3;
-
-    // Type of widget that was involved in triggering this event.
-    optional android.stats.textclassifier.WidgetType widget_type = 4;
-
-    // Detected language.
-    optional string language_tag = 5;
-
-    // Score of the detected language.
-    optional float score = 6;
-
-    // Position of this action.
-    optional int32 action_index = 7;
-
-    // Name of source package.
-    optional string package_name = 8;
-}
-
-/**
- * Information about an OTA update attempt by update_engine.
- * Logged from platform/system/update_engine/metrics_reporter_android.cc
- */
-message UpdateEngineUpdateAttemptReported {
-    // The number of attempts for the update engine to apply a given payload.
-    optional int32 attempt_number = 1;
-
-    optional android.stats.otaupdate.PayloadType payload_type = 2;
-
-    // The total time in minutes for the update engine to apply a given payload.
-    // The time is calculated by calling clock_gettime() / CLOCK_BOOTTIME; and
-    // it's increased when the system is sleeping.
-    optional int32 duration_boottime_in_minutes = 3;
-
-    // The total time in minutes for the update engine to apply a given payload.
-    // The time is calculated by calling clock_gettime() / CLOCK_MONOTONIC_RAW;
-    // and it's not increased when the system is sleeping.
-    optional int32 duration_monotonic_in_minutes = 4;
-
-    // The size of the payload in MiBs.
-    optional int32 payload_size_mib = 5;
-
-    // The attempt result reported by the update engine for an OTA update.
-    optional android.stats.otaupdate.AttemptResult attempt_result = 6;
-
-    // The error code reported by the update engine after an OTA update attempt
-    // on A/B devices.
-    optional android.stats.otaupdate.ErrorCode error_code = 7;
-
-    // The build fingerprint of the source system. The value is read from a
-    // system property when the device takes the update. e.g.
-    // Android/aosp_sailfish/sailfish:10/QP1A.190425.004/5507117:userdebug/test-keys
-    optional string source_fingerprint = 8;
-
-    // Size of super partition.
-    optional int64 super_partition_size_bytes = 9;
-
-    // Size of current slot within the super partition.
-    optional int64 slot_size_bytes = 10;
-
-    // Free space available in the super partition.
-    optional int64 super_free_space_bytes = 11;
-}
-
-/**
- * Information about all the attempts the device make before finishing the
- * successful update.
- * Logged from platform/system/update_engine/metrics_reporter_android.cc
- */
-message UpdateEngineSuccessfulUpdateReported {
-    // The number of attempts for the update engine to apply the payload for a
-    // successful update.
-    optional int32 attempt_count = 1;
-
-    optional android.stats.otaupdate.PayloadType payload_type = 2;
-
-    optional int32 payload_size_mib = 3;
-
-    // The total number of bytes downloaded by update_engine since the last
-    // successful update.
-    optional int32 total_bytes_downloaded_mib = 4;
-
-    // The ratio in percentage of the over-downloaded bytes compared to the
-    // total bytes needed to successfully install the update. e.g. 200 if we
-    // download 200MiB in total for a 100MiB package.
-    optional int32 download_overhead_percentage = 5;
-
-    // The total time in minutes for the update engine to apply the payload for a
-    // successful update.
-    optional int32 total_duration_minutes = 6;
-
-    // The number of reboot of the device during a successful update.
-    optional int32 reboot_count = 7;
-}
-
-/**
- * Reported when the RebootEscrow HAL has attempted to recover the escrowed
- * key to indicate whether it was successful or not.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
- */
-message RebootEscrowRecoveryReported {
-    optional bool successful = 1;
-}
-
-/**
- * Global display pipeline metrics reported by SurfaceFlinger.
- * Metrics exist beginning in Android 11.
- * Pulled from:
- *    frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
- */
-message SurfaceflingerStatsGlobalInfo {
-    // Total number of frames presented during the tracing period
-    optional int64 total_frames = 1;
-    // Total number of frames missed
-    optional int64 missed_frames = 2;
-    // Total number of frames that fell back to client composition
-    optional int64 client_composition_frames = 3;
-    // Total time the display was turned on
-    optional int64 display_on_millis = 4;
-    // Total time that was spent performing animations.
-    // This is derived from the present-to-present layer histogram
-    optional int64 animation_millis = 5;
-    // Total number of event connections tracked by SurfaceFlinger at the time
-    // of this pull. If this number grows prohibitively large, then this can
-    // cause jank due to resource contention.
-    optional int32 event_connection_count = 6;
-    // Set of timings measured from when SurfaceFlinger began compositing a
-    // frame, until the frame was requested to be presented to the display. This
-    // measures SurfaceFlinger's total CPU walltime on the critical path per
-    // frame.
-    optional FrameTimingHistogram frame_duration = 7
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Set of timings measured from when SurfaceFlinger first began using the
-    // GPU to composite a frame, until the GPU has finished compositing that
-    // frame. This measures the total additional time SurfaceFlinger needed to
-    // perform due to falling back into GPU composition.
-    optional FrameTimingHistogram render_engine_timing = 8
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Number of frames where SF saw a frame, based on its frame timeline.
-    // Frame timelines may include transactions without updating buffer contents.
-    // Introduced in Android 12.
-    optional int32 total_timeline_frames = 9;
-    // Number of frames where SF saw a janky frame.
-    // Introduced in Android 12.
-    optional int32 total_janky_frames = 10;
-    // Number of janky frames where SF spent a long time on the CPU.
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_with_long_cpu = 11;
-    // Number of janky frames where SF spent a long time on the GPU.
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_with_long_gpu = 12;
-    // Number of janky frames where SF missed the frame deadline, but there
-    // was not an attributed reason (e.g., maybe HWC missed?)
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_sf_unattributed = 13;
-    // Number of janky frames where the app missed the frame deadline, but
-    // there was not an attributed reason
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_app_unattributed = 14;
-
-    // Next ID: 15
-}
-
-/**
- * Per-layer display pipeline metrics reported by SurfaceFlinger.
- * Metrics exist beginning in Android 11.
- * The number of layers uploaded may be restricted due to size limitations.
- * Pulled from:
- *    frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
- */
-message SurfaceflingerStatsLayerInfo {
-    // UID of the application who submitted this layer for presentation
-    // This is intended to be used as a dimension for surfacing rendering
-    // statistics to applications.
-    // Introduced in Android 12.
-    optional int32 uid = 12 [(is_uid) = true];
-    // The layer for this set of metrics
-    // In many scenarios the package name is included in the layer name, e.g.,
-    // layers created by Window Manager. But this is not a guarantee - in the
-    // general case layer names are arbitrary debug names.
-    optional string layer_name = 1;
-    // Total number of frames presented
-    optional int64 total_frames = 2;
-    // Total number of dropped frames while latching a buffer for this layer.
-    optional int64 dropped_frames = 3;
-    // Set of timings measured between successive presentation timestamps.
-    optional FrameTimingHistogram present_to_present = 4
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Set of timings measured from when an app queued a buffer for
-    // presentation, until the buffer was actually presented to the
-    // display.
-    optional FrameTimingHistogram post_to_present = 5
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Set of timings measured from when a buffer is ready to be presented,
-    // until the buffer was actually presented to the display.
-    optional FrameTimingHistogram acquire_to_present = 6
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Set of timings measured from when a buffer was latched by
-    // SurfaceFlinger, until the buffer was presented to the display
-    optional FrameTimingHistogram latch_to_present = 7
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Set of timings measured from the desired presentation to the actual
-    // presentation time
-    optional FrameTimingHistogram desired_to_present = 8
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Set of timings measured from when an app queued a buffer for
-    // presentation, until the buffer was ready to be presented.
-    optional FrameTimingHistogram post_to_acquire = 9
-        [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Frames missed latch because the acquire fence didn't fire
-    optional int64 late_acquire_frames = 10;
-    // Frames latched early because the desired present time was bad
-    optional int64 bad_desired_present_frames = 11;
-    // Number of frames where SF saw a frame, based on its frame timeline.
-    // Frame timelines may include transactions without updating buffer contents.
-    // Introduced in Android 12.
-    optional int32 total_timeline_frames = 13;
-    // Number of frames where SF saw a janky frame.
-    // Introduced in Android 12.
-    optional int32 total_janky_frames = 14;
-    // Number of janky frames where SF spent a long time on the CPU.
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_with_long_cpu = 15;
-    // Number of janky frames where SF spent a long time on the GPU.
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_with_long_gpu = 16;
-    // Number of janky frames where SF missed the frame deadline, but there
-    // was not an attributed reason (e.g., maybe HWC missed?)
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_sf_unattributed = 17;
-    // Number of janky frames where the app missed the frame deadline, but
-    // there was not an attributed reason
-    // Introduced in Android 12.
-    optional int32 total_janky_frames_app_unattributed = 18;
-
-    // Next ID: 19
-}
-
-/**
- * Histogram of frame counts bucketed by time in milliseconds.
- * Because of size limitations, we hard-cap the number of buckets, with
- * buckets for corresponding to larger milliseconds being less precise.
- */
-message FrameTimingHistogram {
-    // Timings in milliseconds that describes a set of histogram buckets
-    repeated int32 time_millis_buckets = 1;
-    // Number of frames that match to each time_millis, i.e. the bucket
-    // contents
-    // It's required that len(time_millis) == len(frame_count)
-    repeated int64 frame_counts = 2;
-}
-
-/**
- * Janky event as reported by SurfaceFlinger.
- * This event is intended to be consumed by a Perfetto subscriber for
- * automated trace collection.
- *
- * Logged from:
- *    frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
- */
-message DisplayJankReported {
-    // Informational field for how long the janky event lasted in milliseconds
-    optional int64 event_duration_millis = 1;
-    // Number of frame deadlines missed, where SurfaceFlinger failed to update
-    // the display on time.
-    optional int32 present_deadlines_missed = 2;
-}
-
-/**
- * Information about camera facing and API level usage.
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java
- */
-message CameraActionEvent {
-    // Camera session duration in milliseconds if action is SESSION.
-    // 0 if action is OPEN or CLOSE.
-    optional int64 duration_millis = 1;
-
-    // Camera API level used.
-    // 1 for camera1 API, and 2 for camera2 API.
-    optional int32 api_level = 2;
-
-    // Name of client package
-    optional string package_name = 3;
-
-    // Camera facing
-    enum Facing {
-        UNKNOWN = 0;
-        BACK = 1;
-        FRONT = 2;
-        EXTERNAL = 3;
-    }
-    optional Facing facing = 4;
-
-    // Camera ID
-    optional string camera_id = 5;
-
-    // Camera action type
-    enum Action {
-        UNKNOWN_ACTION = 0;
-        OPEN = 1;
-        CLOSE = 2;
-        SESSION = 3;
-    }
-    optional Action action = 6;
-
-    // Whether the client is accessing camera using ndk
-    optional bool is_ndk = 7;
-
-    // Action OPEN: Open latency
-    // Action CLOSE: Close latency
-    // Action SESSION: Camera session creation duration.
-    //                 If this entry is reusing an existing session, the value is -1.
-    optional int32 latency_millis = 8;
-
-    // session type: 0 for normal mode, 1 for constrained high speed mode
-    optional int32 operating_mode = 9;
-
-    // If actioh is SESSION: number of internal reconfigurations
-    // Else: 0
-    optional int32 internal_reconfig = 10;
-
-    // Number of requests for this capture session. Only applicable to SESSION
-    // action.
-    optional int64 request_count = 11;
-    // Number of result errors. Only applicable to SESSION action.
-    optional int64 result_error_count = 12;
-    // Whether the device runs into error state.
-    optional bool device_error = 13;
-
-    // If action is SESSION: Stream states
-    // Else: stream_count = 0
-    optional int32 stream_count = 14;
-    optional android.stats.camera.CameraStreamProto stream_1 = 15
-    [(android.os.statsd.log_mode) = MODE_BYTES];
-    optional android.stats.camera.CameraStreamProto stream_2 = 16
-    [(android.os.statsd.log_mode) = MODE_BYTES];
-    optional android.stats.camera.CameraStreamProto stream_3 = 17
-    [(android.os.statsd.log_mode) = MODE_BYTES];
-    optional android.stats.camera.CameraStreamProto stream_4 = 18
-    [(android.os.statsd.log_mode) = MODE_BYTES];
-    optional android.stats.camera.CameraStreamProto stream_5 = 19
-    [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs when a compatibility change is affecting an app.
- *
- * Logged from:
- *   frameworks/base/core/java/android/app/AppCompatCallbacks.java and
- *   frameworks/base/services/core/java/com/android/server/compat/PlatformCompat.java
- */
-message AppCompatibilityChangeReported {
-    // The UID of the app being affected by the compatibilty change.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The ID of the change affecting the app.
-    optional int64 change_id = 2;
-
-    enum State {
-        UNKNOWN_STATE = 0;
-        ENABLED = 1;
-        DISABLED = 2;
-        LOGGED = 3;
-    }
-
-    // The state of the change - if logged from gating whether it was enabled or disabled, or just
-    // logged otherwise.
-    optional State state = 3;
-
-    enum Source {
-        UNKNOWN_SOURCE = 0;
-        APP_PROCESS = 1;
-        SYSTEM_SERVER = 2;
-    }
-
-    // Where it was logged from.
-    optional Source source = 4;
-
-}
-
-/**
- * Logged from
- *     external/perfetto/src/perfetto_cmd/perfetto_cmd.cc
- */
-message PerfettoUploaded {
-    enum Event {
-        PERFETTO_UNDEFINED = 0;
-        PERFETTO_TRACE_BEGIN = 1;
-        PERFETTO_BACKGROUND_TRACE_BEGIN = 2;
-        PERFETTO_ON_CONNECT = 3;
-        PERFETTO_ON_TRACING_DISABLED = 4;
-        PERFETTO_UPLOAD_DROPBOX_BEGIN = 5;
-        PERFETTO_UPLOAD_DROPBOX_SUCCESS = 6;
-        PERFETTO_UPLOAD_DROPBOX_FAILURE = 7;
-        PERFETTO_UPLOAD_INCIDENT_BEGIN = 8;
-        PERFETTO_UPLOAD_INCIDENT_SUCCESS = 9;
-        PERFETTO_UPLOAD_INCIDENT_FAILURE = 10;
-        PERFETTO_FINALIZE_TRACE_AND_EXIT = 11;
-        PERFETTO_TRIGGER_BEGIN = 12;
-        PERFETTO_TRIGGER_SUCCESS = 13;
-        PERFETTO_TRIGGER_FAILURE = 14;
-        PERFETTO_HIT_GUARDRAILS = 15;
-        PERFETTO_ON_TIMEOUT = 16;
-        PERFETTO_NOT_UPLOADING_EMPTY_TRACE = 17;
-    }
-
-    // Which stage of the pipeline we are reporting from.
-    optional Event event = 1;
-
-    // UUID matching the one set inside the SystemInfo trace packet.
-    optional int64 trace_uuid_lsb = 2;
-    optional int64 trace_uuid_msb = 3;
-}
-
-/**
- * Pulls client metrics on data transferred via Vehicle Maps Service.
- * Metrics are keyed by uid + layer.
- *
- * Pulled from:
- *   packages/services/Car/service/src/com/android/car/stats/CarStatsService.java
- */
-message VmsClientStats {
-    // UID of the VMS client app
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // VMS layer definition
-    optional int32 layer_type = 2;
-    optional int32 layer_channel = 3;
-    optional int32 layer_version = 4;
-
-    // Bytes and packets sent by the client for the layer
-    optional int64 tx_bytes = 5;
-    optional int64 tx_packets = 6;
-
-    // Bytes and packets received by the client for the layer
-    optional int64 rx_bytes = 7;
-    optional int64 rx_packets = 8;
-
-    // Bytes and packets dropped due to client error
-    optional int64 dropped_bytes = 9;
-    optional int64 dropped_packets = 10;
-}
-
-/**
- * State of a dangerous permission requested by a package - sampled
- * Pulled from: StatsCompanionService.java with data obtained from PackageManager API
-*/
-message DangerousPermissionStateSampled {
-    // Name of the permission
-    optional string permission_name = 1;
-
-    // Uid of the package
-    optional int32 uid = 2 [(is_uid) = true];
-
-    // If the permission is granted to the uid
-    optional bool is_granted = 3;
-
-    // Permission flags as per android.content.pm.PermissionFlags
-    optional int32 permission_flags = 4;
-}
-
-/**
- * HWUI stats for a given app.
- */
-message GraphicsStats {
-    // The package name of the app
-    optional string package_name = 1;
-
-    // The version code of the app
-    optional int64 version_code = 2;
-
-    // The start & end timestamps in UTC as
-    // milliseconds since January 1, 1970
-    // Compatible with java.util.Date#setTime()
-    optional int64 start_millis = 3;
-
-    optional int64 end_millis = 4;
-
-    // HWUI renders pipeline type: GL (1) or Vulkan (2).
-    enum PipelineType {
-        UNKNOWN = 0;
-        GL = 1;
-        VULKAN = 2;
-    }
-
-    // HWUI renders pipeline type: GL or Vulkan.
-    optional PipelineType pipeline = 5;
-
-    // Distinct frame count.
-    optional int32 total_frames = 6;
-
-    // Number of "missed vsync" events.
-    optional int32 missed_vsync_count = 7;
-
-    // Number of frames in triple-buffering scenario (high input latency)
-    optional int32 high_input_latency_count = 8;
-
-    // Number of "slow UI thread" events.
-    optional int32 slow_ui_thread_count = 9;
-
-    // Number of "slow bitmap upload" events.
-    optional int32 slow_bitmap_upload_count = 10;
-
-    // Number of "slow draw" events.
-    optional int32 slow_draw_count = 11;
-
-    // Number of frames that missed their deadline (aka, visibly janked)
-    optional int32 missed_deadline_count = 12;
-
-    // The frame time histogram for the package
-    optional FrameTimingHistogram cpu_histogram = 13
-    [(android.os.statsd.log_mode) = MODE_BYTES];
-
-    // The gpu frame time histogram for the package
-    optional FrameTimingHistogram gpu_histogram = 14
-    [(android.os.statsd.log_mode) = MODE_BYTES];
-
-    // UI mainline module version.
-    optional int64 version_ui_module = 15;
-
-    // If true, these are HWUI stats for up to a 24h period for a given app from today.
-    // If false, these are HWUI stats for a 24h period for a given app from the last complete
-    // day (yesterday). Stats from yesterday stay constant, while stats from today may change as
-    // more apps are running / rendering.
-    optional bool is_today = 16;
-}
-
-/**
- * Message related to dangerous (runtime) app ops access
- */
-message RuntimeAppOpAccess {
-    // Uid of the package accessing app op
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Name of the package accessing app op
-    optional string package_name = 2;
-
-    // deprecated - set to empty string
-    optional string op_deprecated = 3 [deprecated = true];
-
-    // attribution_tag; provided by developer when accessing related API, limited at 50 chars by
-    // API. Attributions must be provided through manifest using <attribution> tag available in R
-    // and above.
-    optional string attribution_tag = 4;
-
-    // message related to app op access, limited to 600 chars by API
-    optional string message = 5;
-
-    enum SamplingStrategy {
-        DEFAULT = 0;
-        UNIFORM = 1;
-        RARELY_USED = 2;
-        BOOT_TIME_SAMPLING = 3;
-        UNIFORM_OPS = 4;
-    }
-
-    // sampling strategy used to collect this message
-    optional SamplingStrategy sampling_strategy = 6;
-
-    // operation id
-    optional android.app.AppOpEnum op = 7 [default = APP_OP_NONE];
-}
-
-/*
- * Logs userspace reboot outcome and duration.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/server/BootReceiver.java
- */
-message UserspaceRebootReported {
-    // Possible outcomes of userspace reboot.
-    enum Outcome {
-        // Default value in case platform failed to determine the outcome.
-        OUTCOME_UNKNOWN = 0;
-        // Userspace reboot succeeded (i.e. boot completed without a fall back to hard reboot).
-        SUCCESS = 1;
-        // Userspace reboot shutdown sequence was aborted.
-        FAILED_SHUTDOWN_SEQUENCE_ABORTED = 2;
-        // Remounting userdata into checkpointing mode failed.
-        FAILED_USERDATA_REMOUNT = 3;
-        // Device didn't finish booting before timeout and userspace reboot watchdog issued a hard
-        // reboot.
-        FAILED_USERSPACE_REBOOT_WATCHDOG_TRIGGERED = 4;
-    }
-    // Outcome of userspace reboot. Always set.
-    optional Outcome outcome = 1;
-    // Duration of userspace reboot in case it has a successful outcome.
-    // Duration is measured as time between userspace reboot was initiated and until boot completed
-    // (e.g. sys.boot_completed=1).
-    optional int64 duration_millis = 2;
-    // State of primary user's (user0) credential encryption storage.
-    enum UserEncryptionState {
-        // Default value.
-        USER_ENCRYPTION_STATE_UNKNOWN = 0;
-        // Credential encrypted storage is unlocked.
-        UNLOCKED = 1;
-        // Credential encrypted storage is locked.
-        LOCKED = 2;
-    }
-    // State of primary user's encryption storage at the moment boot completed. Always set.
-    optional UserEncryptionState user_encryption_state = 3;
-}
-
-/*
- * Logs integrity check information during each install.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
- */
-message IntegrityCheckResultReported {
-    optional string package_name = 1;
-    optional string app_certificate_hash = 2;
-    optional int64 version_code = 3;
-    optional string installer_package_name = 4;
-    enum Response {
-        UNKNOWN = 0;
-        ALLOWED = 1;
-        REJECTED = 2;
-        FORCE_ALLOWED = 3;
-    }
-    optional Response response = 5;
-    // An estimate on the cause of the response. This will only be populated for
-    // REJECTED and FORCE_ALLOWED
-    optional bool caused_by_app_cert_rule = 6;
-    optional bool caused_by_installer_rule = 7;
-}
-
-/**
- * Logs the information about the rules and the provider whenever rules are
- * pushed into AppIntegrityManager.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
- */
-message IntegrityRulesPushed {
-    optional bool success = 1;
-    // Package name of the app that pushed the rules.
-    optional string rule_provider = 2;
-    // Version string of arbitrary format provided by the rule provider to
-    // identify the rules.
-    optional string rule_version = 3;
-}
-
-/**
- * Logs when a cell broadcast message is received on the device.
- *
- * Logged from Cell Broadcast module and platform:
- *   packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
- *   packages/apps/CellBroadcastReceiver/
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
- */
-message CellBroadcastMessageReported {
-    // The type of Cell Broadcast message
-    enum CbType {
-        UNKNOWN_TYPE = 0;
-        GSM = 1;
-        CDMA = 2;
-        CDMA_SPC = 3;
-    }
-
-    // The parts of the cell broadcast message pipeline
-    enum ReportSource {
-        UNKNOWN_SOURCE = 0;
-        FRAMEWORK = 1;
-        CB_SERVICE = 2;
-        CB_RECEIVER_APP = 3;
-    }
-
-    // GSM, CDMA, CDMA-SCP
-    optional CbType type = 1;
-
-    // The source of the report
-    optional ReportSource source = 2;
-}
-
-/**
- * Logs when a cell broadcast message is filtered out, or otherwise intentionally not sent to CBR.
- *
- * Logged from CellBroadcastService module:
- *   packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
- */
-message CellBroadcastMessageFiltered {
-    enum FilterReason {
-        NOT_FILTERED = 0;
-        DUPLICATE_MESSAGE = 1;
-        GEOFENCED_MESSAGE = 2;
-        AREA_INFO_MESSAGE = 3;
-    }
-
-    // GSM, CDMA, CDMA-SCP
-    optional CellBroadcastMessageReported.CbType type = 1;
-
-    // The source of the report
-    optional FilterReason filter = 2;
-}
-
-/**
- * Logs when an error occurs while handling a cell broadcast message;
- *
- * Logged from CellBroadcastService module:
- *   packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
- */
-message CellBroadcastMessageError {
-    // The type of error raised when trying to handle a cell broadcast message
-    enum ErrorType {
-        UNKNOWN_TYPE = 0;
-        CDMA_DECODING_ERROR = 1;
-        CDMA_SCP_EMPTY = 2;
-        CDMA_SCP_HANDLING_ERROR = 3;
-        GSM_INVALID_HEADER_LENGTH = 4;
-        GSM_UNSUPPORTED_HEADER_MESSAGE_TYPE = 5;
-        GSM_UNSUPPORTED_HEADER_DATA_CODING_SCHEME = 6;
-        GSM_INVALID_PDU = 7;
-        GSM_INVALID_GEO_FENCING_DATA = 8;
-        GSM_UMTS_INVALID_WAC = 9;
-        FAILED_TO_INSERT_TO_DB = 10;
-        UNEXPECTED_GEOMETRY_FROM_FWK = 11;
-        UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12;
-        UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13;
-        UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14;
-        NO_CONNECTION_TO_CB_SERVICE = 15;
-    }
-
-    // What kind of error occurred
-    optional ErrorType type = 1;
-
-    // Exception message (or log message) associated with the error (max 1000 chars)
-    optional string exception_message = 2;
-}
-
-/**
- * Logs when a TV Input Service Session changes tune state
- * This is atom ID 327.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/tv/TvInputManagerService.java
- */
-message TifTuneStateChanged {
-
-    // Tv Input Service uid, TV Player uid
-    repeated AttributionNode attribution_node = 1 [
-        (state_field_option).primary_field_first_uid = true
-    ];
-    optional android.stats.tv.TifTuneState state = 2 [
-        (state_field_option).exclusive_state = true,
-        (state_field_option).default_state_value = 0,
-        (state_field_option).nested = false
-    ];
-    // This a globally unique 128 bit random number created by TvInputManagerService when
-    // android.media.tv.TvInputManager#createSession is called.
-    // It is has no device or user association.
-    // See android.media.tv.TvInputService.onCreateSession(java.lang.String, java.lang.String)
-    // WARNING: Any changes to this field should be carefully reviewed for privacy.
-    //          Inspect the code at
-    //          framework/base/cmds/statsd/src/atoms.proto
-    //               TifTuneState
-    //          frameworks/base/services/core/java/com/android/server/tv/TvInputManagerService.java
-    //              logTuneStateChanged
-    //              BinderService.createSession
-    //              SessionState.sessionId
-    optional string tif_session_id = 3 [(state_field_option).primary_field = true];
-}
-
-/**
- * Logs when a tune occurs through device's Frontend.
- * This is atom ID 276.
- *
- * Logged from:
- *   frameworks/base/media/java/android/media/tv/tuner/Tuner.java
- */
-message TvTunerStateChanged {
-    enum State {
-        UNKNOWN = 0;
-        TUNING = 1; // Signal is tuned
-        LOCKED = 2;    // the signal is locked
-        NOT_LOCKED = 3; // the signal isn’t locked.
-        SIGNAL_LOST = 4; // the signal was locked, but is lost now.
-        SCANNING = 5; // the signal is scanned
-        SCAN_STOPPED = 6; // the scan is stopped.
-    }
-    // The uid of the application that sent this custom atom.
-    optional int32 uid = 1 [(is_uid) = true];
-    //  new state
-    optional State state = 2;
-}
-
-/**
- * Logs the status of a dvr playback or record.
- * This is atom ID 279.
- *
- * Logged from:
- *   frameworks/base/media/java/android/media/tv/tuner/dvr
- */
-message TvTunerDvrStatus {
-    enum Type {
-        UNKNOWN_TYPE = 0;
-        PLAYBACK = 1; // is a playback
-        RECORD = 2; // is a record
-    }
-    enum State {
-        UNKNOWN_STATE = 0;
-        STARTED = 1; // DVR is started
-        STOPPED = 2; // DVR is stopped
-    }
-    // The uid of the application that sent this custom atom.
-    optional int32 uid = 1 [(is_uid) = true];
-    // DVR type
-    optional Type type = 2;
-    //  DVR state
-    optional State state = 3;
-    //  Identify the segment of a record or playback
-    optional int32 segment_id = 4;
-    // indicate how many overflow or underflow happened between started to stopped
-    optional int32 overflow_underflow_count = 5;
-}
-
-/**
- * Logs when a cas session opened through MediaCas.
- * This is atom ID 280.
- *
- * Logged from:
- *   frameworks/base/media/java/android/media/MediaCas.java
- */
-message TvCasSessionOpenStatus {
-    enum State {
-        UNKNOWN = 0;
-        SUCCEEDED = 1; // indicate that the session is opened successfully.
-        FAILED = 2; // indicate that the session isn’t opened successfully.
-    }
-    // The uid of the application that sent this custom atom.
-    optional int32 uid = 1 [(is_uid) = true];
-    //  Cas system Id
-    optional int32 cas_system_id = 2;
-    // State of the session
-    optional State state = 3;
-}
-
-/**
- * Logs for ContactsProvider general usage.
- * This is atom ID 301.
- *
- * Logged from:
- *   packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java
- */
-message ContactsProviderStatusReported {
-    enum ApiType {
-        UNKNOWN_API = 0;
-        QUERY = 1;
-        // INSERT includes insert and bulkInsert, and inserts triggered by applyBatch.
-        INSERT = 2;
-        // UPDATE and DELETE includes update/delete and the ones triggered by applyBatch.
-        UPDATE = 3;
-        DELETE = 4;
-    }
-
-    enum ResultType {
-        UNKNOWN_RESULT = 0;
-        SUCCESS = 1;
-        FAIL = 2;
-        ILLEGAL_ARGUMENT = 3;
-        UNSUPPORTED_OPERATION = 4;
-    }
-
-    enum CallerType {
-        UNSPECIFIED_CALLER_TYPE = 0;
-        CALLER_IS_SYNC_ADAPTER = 1;
-        CALLER_IS_NOT_SYNC_ADAPTER = 2;
-    }
-
-    optional ApiType api_type = 1;
-    // Defined in
-    // packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java
-    optional int32 uri_type = 2;
-    optional CallerType caller_type = 3;
-    optional ResultType result_type = 4;
-    optional int32 result_count = 5;
-    optional int64 latency_micros = 6;
-}
-
-/**
- * Logs when an app is frozen or unfrozen.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/CachedAppOptimizer.java
- */
-message AppFreezeChanged {
-    // The type of event.
-    enum Action {
-        UNKNOWN = 0;
-        FREEZE_APP = 1;
-        UNFREEZE_APP = 2;
-    }
-    optional Action action = 1;
-
-    // Pid of the process being frozen.
-    optional int32 pid = 2;
-
-    // Name of the process being frozen.
-    optional string process_name = 3;
-
-    // Time since last unfrozen.
-    optional int64 time_unfrozen_millis = 4;
-}
-
-/**
- * Pulls information for a single voice call.
- *
- * Each pull creates multiple atoms, one for each call. The sequence is randomized when pulled.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message VoiceCallSession {
-    // Bearer (IMS or CS) when the call started.
-    optional android.telephony.CallBearerEnum bearer_at_start = 1;
-
-    // Bearer (IMS or CS) when the call ended.
-    // The bearer may change during the call, e.g. due to SRVCC.
-    optional android.telephony.CallBearerEnum bearer_at_end = 2;
-
-    // Direction of the call (incoming or outgoing).
-    optional android.telephony.CallDirectionEnum direction = 3;
-
-    // Time spent setting up the call.
-    optional android.telephony.CallSetupDurationEnum setup_duration = 4;
-
-    // Whether the call ended before the setup was completed.
-    optional bool setup_failed = 5;
-
-    // IMS reason code or CS disconnect cause.
-    // For IMS, see: frameworks/base/telephony/java/android/telephony/ims/ImsReasonInfo.java
-    // For CS, see: frameworks/base/telephony/java/android/telephony/DisconnectCause.java
-    optional int32 disconnect_reason_code = 6;
-
-    // IMS extra code or CS precise disconnect cause.
-    // For IMS, this code is vendor-specific
-    // For CS, see: frameworks/base/telephony/java/android/telephony/PreciseDisconnectCause.java
-    optional int32 disconnect_extra_code = 7;
-
-    // IMS extra message or CS vendor cause.
-    optional string disconnect_extra_message = 8;
-
-    // Radio access technology (RAT) used when call started.
-    optional android.telephony.NetworkTypeEnum rat_at_start = 9;
-
-    // Radio access technology (RAT) used when call terminated.
-    optional android.telephony.NetworkTypeEnum rat_at_end = 10;
-
-    // Number of times RAT changed during the call.
-    optional int64 rat_switch_count = 11;
-
-    // A bitmask of all codecs used during the call.
-    // See: frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
-    optional int64 codec_bitmask = 12;
-
-    // Number of other calls going on during call setup, for the same SIM slot.
-    optional int32 concurrent_call_count_at_start = 13;
-
-    // Number of other calls going on during call termination, for the same SIM slot.
-    optional int32 concurrent_call_count_at_end = 14;
-
-    // Index of the SIM used, 0 for single-SIM devices.
-    optional int32 sim_slot_index = 15;
-
-    // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
-    optional bool is_multi_sim = 16;
-
-    // Whether the call was made with an eSIM profile.
-    optional bool is_esim = 17;
-
-    // Carrier ID of the SIM card.
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 18;
-
-    // Whether an SRVCC has been completed successfully for this call.
-    optional bool srvcc_completed = 19;
-
-    // Number of SRVCC failures.
-    optional int64 srvcc_failure_count = 20;
-
-    // Number of SRVCC cancellations.
-    optional int64 srvcc_cancellation_count = 21;
-
-    // Whether the Real-Time Text (RTT) was ever used in the call (rather than whether RTT was
-    // enabled in the dialer's settings).
-    optional bool rtt_enabled = 22;
-
-    // Whether this was an emergency call.
-    optional bool is_emergency = 23;
-
-    // Whether the call was performed while roaming.
-    optional bool is_roaming = 24;
-
-    // A random number used as the dimension field to pull multiple atoms.
-    optional int32 dimension = 25;
-
-    // Signal strength at the end of the call. This value is applicable to both cellular and WiFi.
-    optional android.telephony.SignalStrengthEnum signal_strength_at_end = 26;
-
-    // Band at the end of the call. Value 0 is used if the band is unknown.
-    // See GeranBands, UtranBands and EutranBands in IRadio interface, depending on the RAT at
-    // the end of the call.
-    optional int32 band_at_end = 27;
-
-    // Time spent setting up the call in milliseconds.
-    // The time is measured from dial to ringing for outgoing calls, and from answer to connected
-    // for incoming calls.
-    optional int32 setup_duration_millis = 28;
-
-    // Main codec quality. The codec quality was equal to or greater than this value for at least
-    // 70% of the call.
-    optional android.telephony.CodecQuality main_codec_quality = 29;
-
-    // Whether video was enabled at any point during the call.
-    optional bool video_enabled = 30;
-
-    // Radio access technology (RAT) used when call is connected.
-    optional android.telephony.NetworkTypeEnum rat_at_connected = 31;
-
-    // Whether the call was a conference call (applicable only for calls over IMS).
-    optional bool is_multiparty = 32;
-}
-
-/**
- * Pulls voice call radio access technology (RAT) usage.
- *
- * Each pull creates multiple atoms, one for each carrier/RAT, the order of which is irrelevant to
- * time. The atom will be skipped if not enough data is available.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message VoiceCallRatUsage {
-    // Carrier ID (https://source.android.com/devices/tech/config/carrierid).
-    optional int32 carrier_id = 1;
-
-    // Radio access technology.
-    optional android.telephony.NetworkTypeEnum rat = 2;
-
-    // Total duration that voice calls spent on this carrier and RAT, rounded to 5 minute.
-    optional int64 total_duration_seconds = 3;
-
-    // Total number of calls using this carrier and RAT.
-    // A call is counted once even if it used the RAT multiple times.
-    optional int64 call_count = 4;
-}
-
-/**
- * Pulls amount of time spend in each cellular service state.
- *
- * Each pull creates multiple atoms, one for each SIM slot/carrier/RAT(including ENDC), the order of
- * which is irrelevant to time. If multi SIM settings changes during the period, durations will be
- * counted separately before and after the change. Airplane mode does not count towards durations.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message CellularServiceState {
-    // Radio access technology (RAT) for voice.
-    // NETWORK_TYPE_UNKNOWN when the device is out of service.
-    // NETWORK_TYPE_IWLAN when the device is using VoWiFi.
-    optional android.telephony.NetworkTypeEnum voice_rat = 1;
-
-    // Radio access technology (RAT) for data.
-    // NETWORK_TYPE_UNKNOWN when the device is out of service.
-    // Only cellular RATs are valid and show where the device is camped.
-    optional android.telephony.NetworkTypeEnum data_rat = 2;
-
-    // Whether the device was in roaming (domestic or international) for voice.
-    optional android.telephony.RoamingTypeEnum voice_roaming_type = 3;
-
-    // Whether the device was in roaming (domestic or international) for data.
-    optional android.telephony.RoamingTypeEnum data_roaming_type = 4;
-
-    // Whether the device is on LTE and has access to NR NSA, i.e. cell supports 5G (ENDC) and UE
-    // registration (attach/TAU) indicates ENDC is not restricted.
-    optional bool is_endc = 5;
-
-    // Index of the SIM used, 0 for single-SIM devices.
-    optional int32 sim_slot_index = 6;
-
-    // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
-    optional bool is_multi_sim = 7;
-
-    // Carrier ID of the SIM card.
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 8;
-
-    // Total time spent in this service state, rounded to 5 minutes.
-    optional int32 total_time_seconds = 9;
-}
-
-/**
- * Pulls the number of times cellular data service state switches.
- *
- * Each pull creates multiple atoms, one for each RAT combination, the order of which is irrelevant
- * to time. Switches for different SIM slots, carrier IDs, or multi-SIM settings are counted
- * separately.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message CellularDataServiceSwitch {
-    // Cellular RAT of the DATA domain from where the switch occurred.
-    optional android.telephony.NetworkTypeEnum rat_from = 1;
-
-    // Cellular RAT of the DATA domain to where the switch occurred.
-    optional android.telephony.NetworkTypeEnum rat_to = 2;
-
-    // Index of the SIM used, 0 for single-SIM devices.
-    optional int32 sim_slot_index = 3;
-
-    // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
-    optional bool is_multi_sim = 4;
-
-    // Carrier ID of the SIM card.
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 5;
-
-    // Number of switches from rat_from to rat_to.
-    optional int32 switch_count = 6;
-}
-
-/**
- * Pulls the number of active SIM slots and SIMs/eSIM profiles.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message SimSlotState {
-    // Number of active SIM slots (both physical and eSIM profiles) in the device.
-    optional int32 active_slot_count = 1;
-
-    // Number of SIM cards (both physical and active eSIM profiles).
-    // This number is always equal to or less than the number of active SIM slots.
-    optional int32 sim_count = 2;
-
-    // Number of active eSIM profiles.
-    // This number is always equal to or less than the number of SIMs.
-    optional int32 esim_count = 3;
-}
-
-/**
- * Pulls supported cellular radio access technologies.
- *
- * This atom reports the capabilities of the device, rather than the network it has access to.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message SupportedRadioAccessFamily {
-    // A bitmask of supported radio technologies.
-    // See android.telephony.TelephonyManager.NetworkTypeBitMask.
-    optional int64 network_type_bitmask = 1;
-}
-
-/**
- * Pulls information for a single incoming SMS.
- *
- * Each pull creates multiple atoms, one for each SMS. The sequence is randomized when pulled.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message IncomingSms {
-    // Format of the SMS (3GPP or 3GPP2).
-    optional android.telephony.SmsFormatEnum sms_format = 1;
-
-    // Technology of the SMS (CS or IMS).
-    optional android.telephony.SmsTechEnum sms_tech = 2;
-
-    // Radio access technology (RAT) used for the SMS. It can be IWLAN in case of IMS.
-    optional android.telephony.NetworkTypeEnum rat = 3;
-
-    // Type the SMS.
-    optional android.telephony.SmsTypeEnum sms_type = 4;
-
-    // Number of total parts.
-    optional int32 total_parts = 5;
-
-    // Number of received parts (if smaller than total parts, the SMS was dropped).
-    optional int32 received_parts = 6;
-
-    // Indicates if the incoming SMS was blocked.
-    optional bool blocked = 7;
-
-    // Indicate a specific error handling the SMS
-    optional android.telephony.SmsIncomingErrorEnum error = 8;
-
-    // Whether the SMS was received while roaming.
-    optional bool is_roaming = 9;
-
-    // Index of the SIM used, 0 for single-SIM devices.
-    optional int32 sim_slot_index = 10;
-
-    // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
-    optional bool is_multi_sim = 11;
-
-    // Whether the message was received with an eSIM profile.
-    optional bool is_esim = 12;
-
-    // Carrier ID of the SIM card used for the SMS.
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 13;
-
-    // Random message ID.
-    optional int64 message_id = 14;
-}
-
-/**
- * Pulls information for a single outgoing SMS.
- *
- * Each pull creates multiple atoms, one for each SMS. The sequence is randomized when pulled.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message OutgoingSms {
-    // Format of the SMS (3GPP or 3GPP2).
-    optional android.telephony.SmsFormatEnum sms_format = 1;
-
-    // Technology of the SMS (CS or IMS).
-    optional android.telephony.SmsTechEnum sms_tech = 2;
-
-    // Radio access technology (RAT) used for the SMS. It can be IWLAN in case of IMS.
-    optional android.telephony.NetworkTypeEnum rat = 3;
-
-    // Result of the SMS sending.
-    optional android.telephony.SmsSendResultEnum send_result = 4;
-
-    // Error code
-    // For IMS technology, see @SmsManager.Result in
-    // http://cs/android/frameworks/base/telephony/java/android/telephony/SmsManager.java
-    // For CS technology:
-    //  - GSM format: see GsmSmsErrorCode (3GPP 27.005 clause 3.2.5)
-    //  - CDMA format: see CdmaSmsErrorCode (3GPP2 N.S0005 (IS-41-C) Table 171)
-    optional int32 error_code = 5;
-
-    // Whether the SMS was sent while roaming.
-    optional bool is_roaming = 6;
-
-    // Whether the default SMS application generated the SMS (regardless of which application).
-    optional bool is_from_default_app = 7;
-
-    // Index of the SIM used, 0 for single-SIM devices.
-    optional int32 sim_slot_index = 8;
-
-    // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
-    optional bool is_multi_sim = 9;
-
-    // Whether the message was sent with an eSIM profile.
-    optional bool is_esim = 10;
-
-    // Carrier ID of the SIM card used for the SMS.
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 11;
-
-    // Random message ID.
-    optional int64 message_id = 12;
-
-    // Retry count: 0 for the first attempt and then increasing for each attempt.
-    optional int32 retry_id = 13;
-}
-
-/**
- * Logs information about usage of airplane mode.
- *
- * Logged from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/AirplaneModeStats.java
- */
-message AirplaneMode {
-    // Status of airplane mode
-    optional bool is_enabled = 1;
-
-    // When is_enabled is false, indicates if this was a very short airplane mode toggle
-    // (i.e. airplane mode was disabled after less than 10 seconds from enablement).
-    optional bool short_toggle = 2;
-
-    // Carrier ID of the SIM card.
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 3;
-}
-
-/**
- * Logs information about modem restarts.
- *
- * Logged from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/ModemRestartStats.java
- */
-message ModemRestart {
-    // Software version of the modem, as provided by android.os.Build.getRadioVersion().
-    optional string baseband_version = 1;
-
-    // Reason of the modem restart, as provided in the modemReset indication of IRadio HAL.
-    optional string reason = 2;
-
-    // Carrier ID of the first SIM card.
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 3;
-}
-
-/**
- * Logs the SIM card details when the carrier ID match is not complete.
- *
- * The atom is pushed when a SIM card is initialized and the MCC/MNC is not present in the
- * carrier ID table, or the SIM card contains a GID1 value that is not present in the carrier ID
- * table. This atom is pushed only once for each type of SIM card.
- *
- * Logged from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/CarrierIdMatchStats.java
- */
-message CarrierIdMismatchReported {
-    // Matched carrier ID. The value -1 is used if no match is found.
-    optional int32 carrier_id = 1;
-
-    // MCC/MNC of the SIM card.
-    optional string mcc_mnc = 2;
-
-    // Group identifier (level 1) of the SIM card.
-    optional string gid1 = 3;
-
-    // SPN value of the SIM card.
-    optional string spn = 4;
-
-    // First record of the PNN in the SIM card. This field is populated only if the SPN is missing
-    // or empty.
-    optional string pnn = 5;
-}
-
-/**
- * Logs the version of the carrier ID matching table at first power up and when it is updated.
- *
- * Logged from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/CarrierIdMatchStats.java
- */
-message CarrierIdTableUpdated {
-    // Version of the CarrierId matching table.
-    optional int32 table_version = 1;
-}
-
-/**
- * Pulls the version of the carrier ID matching table.
- *
- * Logged from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message CarrierIdTableVersion {
-    // Version of the CarrierId matching table.
-    optional int32 table_version = 1;
-}
-
-/**
- * Pulls information for a single data call session
- *
- * Each pull creates multiple atoms, one for each data call session.
- * The sequence is randomized when pulled.
- *
- * Pulled from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
- */
-message DataCallSession {
-    // A random number to be used as dimension to capture multiple atoms
-    optional int32 dimension = 1;
-
-    // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
-    optional bool is_multi_sim = 2;
-
-    // Whether the call was made with an eSIM profile.
-    optional bool is_esim = 3;
-
-    // Data profile of this call (for what purpose this call was made)
-    optional android.telephony.DataProfileEnum profile = 4;
-
-    // APN type bitmask of the APN used:
-    // @ApnType in frameworks/base/telephony/java/android/telephony/Annotation.java.
-    optional int32 apn_type_bitmask = 5;
-
-    // Carrier ID of the SIM
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 6;
-
-    // Whether the subscription is roaming
-    optional bool is_roaming = 7;
-
-    // Data RAT when the call ended, can be IWLAN for IMS/MMS, otherwise should be WWAN PS RAT.
-    // In the case that the connection hasn't ended yet, this field holds the current RAT.
-    // In the case the call ended due to Out Of Service (OOS),
-    // this field should be the last known RAT.
-    optional android.telephony.NetworkTypeEnum rat_at_end = 8;
-
-    // Was the data call ended due to OOS
-    optional bool oos_at_end = 9;
-
-    // Number of RAT switches during the data call
-    optional int64 rat_switch_count = 10;
-
-    // Whether the call is on an opportunistic subscription
-    optional bool is_opportunistic = 11;
-
-    // Packet data protocol used
-    optional android.telephony.ApnProtocolEnum ip_type = 12;
-
-    // Whether the data call terminated before being established
-    optional bool setup_failed = 13;
-
-    // Reason why the data call terminated, as in RIL_DataCallFailCause from ril.h
-    optional int32 failure_cause = 14;
-
-    // Suggested retry back-off timer value from RIL
-    optional int32 suggested_retry_millis = 15;
-
-    // Why the data call was deactivated
-    // Set by telephony for MO deactivations (unrelated to failure_cause)
-    optional android.telephony.DataDeactivateReasonEnum deactivate_reason = 16;
-
-    // Duration of the data call, rounded into the closest 5 minutes.
-    optional int64 duration_minutes = 17;
-
-    // Whether the data call is still connected when the atom is collected.
-    optional bool ongoing = 18;
-}
-
-/**
- * Logs data stall recovery event
- *
- * Logged from:
- *   frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
- */
-message DataStallRecoveryReported {
-    // Carrier ID of the SIM
-    // See https://source.android.com/devices/tech/config/carrierid.
-    optional int32 carrier_id = 1;
-
-    // Data RAT when the stall happened
-    optional android.telephony.NetworkTypeEnum rat = 2;
-
-    // Signal strength when stall happened
-    optional android.telephony.SignalStrengthEnum signal_strength = 3;
-
-    // Action taken to recover
-    optional android.telephony.DataStallRecoveryActionEnum action = 4;
-
-    // Whether the subscription is opportunistic
-    optional bool is_opportunistic = 5;
-
-    // Whether the device is in multi-SIM mode
-    optional bool is_multi_sim = 6;
-}
-
-/**
- * Logs gnss stats from location service provider
- *
- * Pulled from:
- *  frameworks/base/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
- */
-message GnssStats {
-    // Number of location reports since boot
-    optional int64 location_reports = 1;
-
-    // Total pulled reports of Location failures since boot
-    optional int64 location_failure_reports = 2;
-
-    // Number of time to first fix reports since boot
-    optional int64 time_to_first_fix_reports = 3;
-
-    // Total pulled reported time to first fix (in milli-seconds) since boot
-    optional int64 time_to_first_fix_millis = 4;
-
-    // Number of position accuracy reports since boot
-    optional int64 position_accuracy_reports = 5;
-
-    // Total pulled reported position accuracy (in meters) since boot
-    optional int64 position_accuracy_meters = 6;
-
-    // Number of top 4 average CN0 reports since boot
-    optional int64 top_four_average_cn0_reports = 7;
-
-    // Total pulled reported of top 4 average CN0 (dB-mHz) since boot
-    optional int64 top_four_average_cn0_db_mhz = 8;
-
-    // Number of l5 top 4 average CN0 reports since boot
-    optional int64 l5_top_four_average_cn0_reports = 9;
-
-    // Total pulled reported of l5 top 4 average CN0 (dB-mHz) since boot
-    optional int64 l5_top_four_average_cn0_db_mhz = 10;
-
-    // Total number of sv status messages reports since boot
-    optional int64 sv_status_reports = 11;
-
-    // Total number of sv status messages reports, where sv is used in fix since boot
-    optional int64 sv_status_reports_used_in_fix = 12;
-
-    // Total number of L5 sv status messages reports since boot
-    optional int64 l5_sv_status_reports = 13;
-
-    // Total number of L5 sv status messages reports, where sv is used in fix since boot
-    optional int64 l5_sv_status_reports_used_in_fix = 14;
-}
-
-/**
- * Logs when an app is moved to a different standby bucket.
- *
- * Logged from:
- *   frameworks/base/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
- */
-message AppStandbyBucketChanged {
-    optional string package_name = 1;
-
-    // Should be 0, 10, 11, 12, etc. where 0 is the owner. See UserHandle for more documentation.
-    optional int32 user_id = 2;
-
-    // These enum values match the constants defined in UsageStatsManager.java.
-    enum Bucket {
-        BUCKET_UNKNOWN = 0;
-        BUCKET_EXEMPTED = 5;
-        BUCKET_ACTIVE = 10;
-        BUCKET_WORKING_SET = 20;
-        BUCKET_FREQUENT = 30;
-        BUCKET_RARE = 40;
-        BUCKET_RESTRICTED = 45;
-        BUCKET_NEVER = 50;
-    }
-    optional Bucket bucket = 3;
-
-    enum MainReason {
-        MAIN_UNKNOWN = 0;
-        MAIN_DEFAULT = 0x0100;
-        MAIN_TIMEOUT = 0x0200;
-        MAIN_USAGE = 0x0300;
-        MAIN_FORCED_BY_USER = 0x0400;
-        MAIN_PREDICTED = 0x0500;
-        MAIN_FORCED_BY_SYSTEM = 0x0600;
-    }
-    optional MainReason main_reason = 4;
-
-    // A more detailed reason for the standby bucket change. The sub reason name is dependent on
-    // the main reason. Values are one of the REASON_SUB_XXX constants defined in
-    // UsageStatsManager.java.
-    optional int32 sub_reason = 5;
-}
-
-/**
-* Reports a started sharesheet transaction.
-*
-* Logged from:
-*   frameworks/base/core/java/com/android/internal/app/ChooserActivity.java
-*/
-message SharesheetStarted {
-    // The event_id (as for UiEventReported).
-    optional int32 event_id = 1;
-    // The calling app's package name.
-    optional string package_name = 2;
-    // An identifier to tie together multiple logs relating to the same share event
-    optional int32 instance_id = 3;
-    // The mime type of the share
-    optional string mime_type = 4;
-    // The number of direct targets the calling app is providing that will be shown.
-    optional int32 num_app_provided_direct_targets = 5;
-    // The number of app targets the calling app is providing that will be shown.
-    optional int32 num_app_provided_app_targets = 6;
-    // True if the share originates from the workprofile
-    optional bool is_workprofile = 7;
-
-    enum SharesheetPreviewType {  // Constants from ChooserActivity.java
-        CONTENT_PREVIEW_TYPE_UNKNOWN = 0;  // Default for proto 2 / 3 compatibility.
-        CONTENT_PREVIEW_IMAGE = 1;  // The preview shown in the sharesheet is an image.
-        CONTENT_PREVIEW_FILE = 2;  // The preview shown in the sharesheet is a file.
-        CONTENT_PREVIEW_TEXT = 3;  // The preview shown in the sharesheet is text.
-    }
-    // How the sharesheet preview is presented.
-    optional SharesheetPreviewType preview_type = 8;
-
-    enum ResolverActivityIntent { // Intents handled by ResolverActivity.java
-        INTENT_DEFAULT = 0;
-        INTENT_ACTION_VIEW = 1;
-        INTENT_ACTION_EDIT = 2;
-        INTENT_ACTION_SEND = 3;
-        INTENT_ACTION_SENDTO = 4;
-        INTENT_ACTION_SEND_MULTIPLE = 5;
-        INTENT_ACTION_IMAGE_CAPTURE = 6;
-        INTENT_ACTION_MAIN = 7;
-    }
-    // The intent being processed (only SEND and SEND_MULTIPLE are system sharesheet)
-    optional ResolverActivityIntent intent_type = 9;
-}
-
-/**
- * Reports a ranking selection event.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/app/ChooserActivity.java (sharesheet)
- */
-message RankingSelected {
-    // The event_id (as for UiEventReported).
-    optional int32 event_id = 1;
-    // The relevant app's package name (can be source or picked package).
-    optional string package_name = 2;
-    // An identifier to tie together multiple logs relating to the same share event.
-    optional int32 instance_id = 3;
-    // Which of the ranked targets got picked, default starting position 0.
-    optional int32 position_picked = 4;
-}
-
-/**
- * Logs when TvSettings UI is interacted at.
- *
- * Logged from: packages/apps/TvSettings
- */
-message TvSettingsUIInteracted {
-
-    /** The UI action category */
-    optional android.app.tvsettings.Action action = 1;
-
-    /** The ID of the entry that the users actioned on */
-    optional android.app.tvsettings.ItemId item_id = 2;
-}
-
-/**
- * Logs information about a package installation using package installer V2 APIs.
- *
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
- */
-message PackageInstallerV2Reported {
-    // Whether this installation uses Incremental File System
-    optional bool is_incremental = 1;
-    // Name of the package that is intended to be installed
-    optional string package_name = 2;
-    // The duration between when the install was requested to when the install has completed
-    optional int64 duration_millis = 3;
-    // Installation result in final integer, which are SystemApi's.
-    // Return_code 1 indicates success.
-    // For full list, see frameworks/base/core/java/android/content/pm/PackageManager.java
-    optional int32 return_code  = 4;
-    // Total size of the APKs installed for this package
-    optional int64 apks_size_bytes = 5;
-}
-
-/**
- * Logs settings provider values.
- *
- * Use DeviceConfig.getProperties to get a list Setting key, query the data from content provider,
- * then write the value to proto.
- *
- */
-message SettingSnapshot {
-
-    // Setting key
-    optional string name = 1;
-
-    enum SettingsValueType {
-        NOTASSIGNED = 0;
-        ASSIGNED_BOOL_TYPE = 1;
-        ASSIGNED_INT_TYPE = 2;
-        ASSIGNED_FLOAT_TYPE = 3;
-        ASSIGNED_STRING_TYPE = 4;
-    };
-    // Setting value type
-    optional SettingsValueType type = 2;
-
-    optional bool bool_value = 3;
-
-    optional int32 int_value = 4;
-
-    optional float float_value = 5;
-
-    optional string str_value = 6;
-
-    // Android user index. 0 for primary user, 10, 11 for secondary or profile user
-    optional int32 user_id = 7;
-}
-
-/**
- * An event logged to indicate that a user journey is about to be performed. This atom includes
- * relevant information about the users involved in the journey. A UserLifecycleEventOccurred event
- * will immediately follow this atom which will describe the event(s) and its state.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/UserController.java
- *   frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java
- */
-message UserLifecycleJourneyReported {
-    // An identifier to track a chain of user lifecycle events occurring (referenced in the
-    // UserLifecycleEventOccurred atom)
-    optional int64 session_id = 1;
-
-    // Indicates what type of user journey this session is related to
-    enum Journey {
-        UNKNOWN = 0; // Undefined user lifecycle journey
-        USER_SWITCH_UI = 1; // A user switch journey where a UI is shown
-        USER_SWITCH_FG = 2; // A user switch journey without a UI shown
-        USER_START = 3; // A user start journey
-        USER_CREATE = 4; // A user creation journey
-    }
-    optional Journey journey = 2;
-    // Which user the journey is originating from - could be -1 for certain phases (eg USER_CREATE)
-    // This integer is a UserIdInt (eg 0 for the system user, 10 for secondary/guest)
-    optional int32 origin_user = 3;
-    // Which user the journey is targeting
-    // This integer is a UserIdInt (eg 0 for the system user, 10 for secondary/guest)
-    optional int32 target_user = 4;
-
-    // What is the user type of the target user
-    // These should be in sync with USER_TYPE_* flags defined in UserManager.java
-    enum UserType {
-        TYPE_UNKNOWN = 0;
-        FULL_SYSTEM = 1;
-        FULL_SECONDARY = 2;
-        FULL_GUEST = 3;
-        FULL_DEMO = 4;
-        FULL_RESTRICTED = 5;
-        PROFILE_MANAGED = 6;
-        SYSTEM_HEADLESS = 7;
-    }
-    optional UserType user_type = 5;
-    // What are the flags attached to the target user
-    optional int32 user_flags = 6;
-}
-
-/**
- * An event logged when a specific user lifecycle event is performed. These events should be
- * correlated with a UserLifecycleJourneyReported atom via the session_id.
- * Note: journeys can span over multiple events, hence some events may share a single session id.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/am/UserController.java
- *   frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java
- */
-message UserLifecycleEventOccurred {
-    // An id which links back to user details (reported in the UserLifecycleJourneyReported atom)
-    optional int64 session_id = 1;
-    // The target user for this event (same as target_user in the UserLifecycleJourneyReported atom)
-    // This integer is a UserIdInt (eg 0 for the system user, 10 for secondary/guest)
-    optional int32 user_id = 2;
-
-    enum Event {
-        UNKNOWN = 0; // Indicates that the associated user journey timed-out or resulted in an error
-        SWITCH_USER = 1; // Indicates that this is a user switch event
-        START_USER = 2; // Indicates that this is a user start event
-        CREATE_USER = 3; // Indicates that this is a user create event
-        USER_RUNNING_LOCKED = 4; // Indicates that user is running in locked state
-        UNLOCKING_USER = 5; // Indicates that this is a user unlocking event
-        UNLOCKED_USER = 6; // Indicates that this is a user unlocked event
-    }
-    optional Event event = 3;
-
-    enum State {
-        NONE = 0; // Indicates the associated event has no start/end defined
-        BEGIN = 1;
-        FINISH = 2;
-    }
-    optional State state = 4; // Represents the state of an event (beginning/ending)
-}
-
-/**
- * Logs when accessibility shortcut clicked.
- *
- * Logged from:
- *   frameworks/base/services/accessibility/java/com/android/server/accessibility
- */
-message AccessibilityShortcutReported {
-    // The accessibility feature(including installed a11y service, framework a11y feature,
-    // and installed a11y activity) package name that is assigned to the accessibility shortcut.
-    optional string package_name = 1;
-
-    // The definition of the accessibility shortcut.
-    // From frameworks/base/core/proto/android/stats/accessibility/accessibility_enums.proto.
-    optional android.stats.accessibility.ShortcutType shortcut_type = 2;
-
-    // The definition of the service status.
-    // From frameworks/base/core/proto/android/stats/accessibility/accessibility_enums.proto.
-    optional android.stats.accessibility.ServiceStatus service_status = 3;
-}
-
-/**
- * Logs when accessibility service status changed.
- *
- * Logged from:
- *   packages/apps/Settings/src/com/android/settings/accessibility
- */
-message AccessibilityServiceReported {
-    // The accessibility service package name.
-    optional string package_name = 1;
-
-    // The definition of the service status.
-    // From frameworks/base/core/proto/android/stats/accessibility/accessibility_enums.proto.
-    optional android.stats.accessibility.ServiceStatus service_status = 2;
-}
-
-/**
- * Logs when display wake up.
- *
- * Logged from:
- *   services/core/java/com/android/server/power/Notifier.java
- */
-
-message DisplayWakeReported {
-    // Wake_up_reason code
-    // If LOWORD(wake_up_reason) = 0
-    //     reference to HIWORD(wake_up_reason) PowerManager.WAKE_REASON_XXX
-    //     else reference wake_up_reason to
-    //     services/core/java/com/android/server/power/Notifier.java#onWakeUp
-    optional int32 wake_up_reason = 1;
-}
-
-/**
- * Logs app usage events.
- */
-message AppUsageEventOccurred {
-    optional int32 uid = 1 [(is_uid) = true];
-    optional string package_name = 2;
-    optional string class_name = 3;
-
-    enum EventType {
-        NONE = 0;
-        MOVE_TO_FOREGROUND = 1;
-        MOVE_TO_BACKGROUND = 2;
-    }
-    optional EventType event_type = 4;
-}
-
-/*
- * Quality metrics logged when EVS cameras are active.
- *
- * Logged from:
- *  packages/services/Car/evs/manager/1.1/Enumerator.cpp
- */
-message EvsUsageStatsReported {
-
-    // Camera identifier to distinguish the source camera device.  This is not
-    // globally unique and therefore cannot be used to identify the user and/or
-    // the device.
-    optional int32 device_id = 1;
-
-    // Peak number of clients during the service
-    optional int32 peak_num_clients = 2;
-
-    // Number of erroneous events during the service
-    optional int32 num_errors = 3;
-
-    // Round trip latency of the very first frame
-    optional int64 first_latency_millis = 4;
-
-    // Average frame round trip latency
-    optional float avg_latency_millis = 5;
-
-    // Peak frame round trip latency
-    optional int64 peak_latency_millis = 6;
-
-    // Total number of frames received
-    optional int64 total_frames = 7;
-
-    // Number of frames ignored
-    optional int64 ignored_frames = 8;
-
-    // Number of dropped frames to synchronize camera devices
-    optional int64 dropped_frames_to_sync = 9;
-
-    // The duration of the service
-    optional int64 duration_millis = 10;
-}
-
-/**
- * Logs audio power usage stats.
- *
- * Pushed from:
- *  frameworks/av/services/mediametrics/AudioPowerUsage.cpp
- */
-message AudioPowerUsageDataReported {
-    /**
-     * Device used for input/output
-     *
-     * All audio devices please refer to below file:
-     * system/media/audio/include/system/audio-base.h
-     *
-     * Define our own enum values because we don't report all audio devices.
-     * Currently, we only report built-in audio devices such as handset, speaker,
-     * built-in mics, common audio devices such as wired headset, usb headset
-     * and bluetooth devices.
-     */
-    enum AudioDevice {
-        OUTPUT_EARPIECE         = 0x1; // handset
-        OUTPUT_SPEAKER          = 0x2; // dual speaker
-        OUTPUT_WIRED_HEADSET    = 0x4; // 3.5mm headset
-        OUTPUT_USB_HEADSET      = 0x8; // usb headset
-        OUTPUT_BLUETOOTH_SCO    = 0x10; // bluetooth sco
-        OUTPUT_BLUETOOTH_A2DP   = 0x20; // a2dp
-        OUTPUT_SPEAKER_SAFE     = 0x40; // bottom speaker
-
-        INPUT_DEVICE_BIT        = 0x40000000; // non-negative positive int32.
-        INPUT_BUILTIN_MIC       = 0x40000001; // buildin mic
-        INPUT_BUILTIN_BACK_MIC  = 0x40000002; // buildin back mic
-        INPUT_WIRED_HEADSET_MIC = 0x40000004; // 3.5mm headset mic
-        INPUT_USB_HEADSET_MIC   = 0x40000008; // usb headset mic
-        INPUT_BLUETOOTH_SCO     = 0x40000010; // bluetooth sco mic
-    }
-    optional AudioDevice audio_device = 1;
-
-    // Duration of the audio in seconds
-    optional int32 duration_secs = 2;
-
-    // Average volume (0 ... 1.0)
-    optional float average_volume = 3;
-
-    enum AudioType {
-        UNKNOWN_TYPE = 0;
-        VOICE_CALL_TYPE = 1; // voice call
-        VOIP_CALL_TYPE = 2; // voip call, including uplink and downlink
-        MEDIA_TYPE = 3; // music and system sound
-        RINGTONE_NOTIFICATION_TYPE = 4; // ringtone and notification
-        ALARM_TYPE = 5; // alarm type
-        // record type
-        CAMCORDER_TYPE = 6; // camcorder
-        RECORD_TYPE = 7;  // other recording
-    }
-    optional AudioType type = 4;
-}
-
-/**
-  * Pulls bytes transferred over WiFi and mobile networks sliced by uid, is_metered, and tag.
-  *
-  * Pulled from:
-  *   StatsPullAtomService, which uses NetworkStatsService to query NetworkStats.
-  */
-message BytesTransferByTagAndMetered {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    optional bool is_metered = 2;
-
-    optional int32 tag = 3;
-
-    optional int64 rx_bytes = 4;
-
-    optional int64 rx_packets = 5;
-
-    optional int64 tx_bytes = 6;
-
-    optional int64 tx_packets = 7;
-}
-
-/*
- * Logs when the Media Output Switcher finishes a media switch operation.
- *
- * Logged from:
- *  packages/apps/Settings/src/com/android/settings/media/MediaOutputSliceWorker.java
- */
-message MediaOutputOpSwitchReported {
-    // Source medium type before switching.
-    optional android.app.settings.mediaoutput.MediumType source = 1;
-
-    // Target medium type after switching.
-    optional android.app.settings.mediaoutput.MediumType target = 2;
-
-    // The result of switching.
-    optional android.app.settings.mediaoutput.SwitchResult result = 3;
-
-    // The detail code of a switching result.
-    optional android.app.settings.mediaoutput.SubResult subresult = 4;
-
-    /*
-     * The package name of a pre-installed app, whose media session is being switched.
-     */
-    optional string media_session_package_name = 5;
-
-    // The amount of available wired devices when a switching is being performed.
-    optional int32 available_wired_device_count = 6;
-
-    // The amount of available Bluetooth devices a switching is being performed.
-    optional int32 available_bt_device_count = 7;
-
-    // The amount of available remote devices when a switching is being performed.
-    optional int32 available_remote_device_count = 8;
-
-    // The amount of applied devices within a remote dynamic group after a switching is done.
-    optional int32 applied_device_count_within_remote_group = 9;
-}
-
-/**
- * Logs when the Assistant is invoked.
- *
- * Logged from:
- *   frameworks/base/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
- */
-message AssistantInvocationReported {
-
-    // The event_id (as for UiEventReported).
-    optional int32 event_id = 1;
-
-    // The registered Assistant's uid and package (as for UiEventReported).
-    optional int32 uid = 2 [(is_uid) = true];
-    optional string package_name = 3;
-
-    // An identifier used to disambiguate which logs refer to a particular invocation of the
-    // Assistant  (as for UiEventReported).
-    optional int32 instance_id = 4;
-
-    // The state of the device at the time of invocation.
-    enum DeviceState {
-        UNKNOWN_DEVICE_STATE = 0;
-        AOD1 = 1;
-        AOD2 = 2;
-        BOUNCER = 3;
-        UNLOCKED_LOCKSCREEN = 4;
-        LAUNCHER_HOME = 5;
-        LAUNCHER_OVERVIEW = 6;
-        LAUNCHER_ALL_APPS = 7;
-        APP_DEFAULT = 8;
-        APP_IMMERSIVE = 9;
-        APP_FULLSCREEN = 10;
-    }
-    optional DeviceState device_state = 5;
-
-    // Whether the Assistant handles were showing at the time of invocation.
-    optional bool assistant_handles_showing = 6;
-}
-
-/**
- * Logs when an AudioRecord finishes running on an audio device
- *
- * Logged from:
- *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
- */
-message MediametricsAudioRecordDeviceUsageReported {
-    // The devices connected to this AudioRecord.
-    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
-    // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    // See audio_device_t in system/media/audio/include/system/audio-base.h
-    optional string devices = 1;
-
-    // The name of the remote device attached to the device, typically available for USB or BT.
-    // This may be empty for a fixed device, or separated by "|" if more than one.
-    optional string device_names = 2;
-
-    // The amount of time spent in the device as measured by the active track in AudioFlinger.
-    optional int64 device_time_nanos = 3;
-
-    // The audio data format used for encoding.
-    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
-    optional string encoding = 4;
-
-    // The client-server buffer framecount.
-    // The framecount is generally between 960 - 48000 for PCM encoding.
-    // The framecount represents raw buffer size in bytes for non-PCM encoding.
-    optional int32 frame_count = 5;
-
-    // The number of audio intervals (contiguous, continuous playbacks).
-    optional int32 interval_count = 6;
-
-    // The sample rate of the AudioRecord.
-    // A number generally between 8000-96000 (frames per second).
-    optional int32 sample_rate = 7;
-
-    // The audio input flags used to construct the AudioRecord.
-    // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t
-    optional string flags = 8;
-
-    // The santized package name of the audio client associated with the AudioRecord.
-    // See getSanitizedPackageNameAndVersionCode() in
-    // frameworks/av/services/mediametrics/MediaMetricsService.cpp
-    optional string package_name = 9;
-
-    // The selected device id (nonzero if a non-default device is selected)
-    optional int32 selected_device_id = 10;
-
-    // The caller of the AudioRecord.
-    // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    optional string caller = 11;
-
-    // The audio source for AudioRecord.
-    // An enumeration from system/media/audio/include/system/audio-base.h audio_source_t
-    optional string source = 12;
-}
-
-/**
- * Logs when an AudioThread finishes running on an audio device
- *
- * Logged from:
- *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
- */
-message MediametricsAudioThreadDeviceUsageReported {
-    // The devices connected to this audio thread.
-    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
-    // (for record threads):
-    // See lookup<INPUT_DEVICE> in frameworks/av/services/mediametrics/AudioTypes.cpp
-    // (for playback threads):
-    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    // See audio_device_t in system/media/audio/include/system/audio-base.h
-    optional string devices = 1;
-
-    // The name of the remote device attached to the device, typically available for USB or BT.
-    // This may be empty for a fixed device, or separated by "|" if more than one.
-    optional string device_names = 2;
-
-    // The amount of time spent in the device as measured by the active track in AudioFlinger.
-    optional int64 device_time_nanos = 3;
-
-    // The audio data format used for encoding.
-    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
-    optional string encoding = 4;
-
-    // The framecount of the buffer delivered to (or from) the HAL.
-    // The framecount is generally ~960 for PCM encoding.
-    // The framecount represents raw buffer size in bytes for non-PCM encoding.
-    optional int32 frame_count = 5;
-
-    // The number of audio intervals (contiguous, continuous playbacks).
-    optional int32 interval_count = 6;
-
-    // The sample rate of the audio thread.
-    // A number generally between 8000-96000 (frames per second).
-    optional int32 sample_rate = 7;
-
-    // The audio flags used to construct the thread
-    // (for record threads):
-    // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t
-    // (for playback threads):
-    // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t
-    optional string flags = 8;
-
-    // The number of underruns encountered for a playback thread or the
-    // number of overruns encountered for a capture thread.
-    optional int32 xruns = 9;
-
-    // The type of thread
-    // A thread type enumeration from
-    // frameworks/av/mediametrics/services/Translate.h
-    optional string type = 10;
-}
-
-/**
- * Logs when an AudioTrack finishes running on an audio device
- *
- * Logged from:
- *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
- */
-message MediametricsAudioTrackDeviceUsageReported {
-    // The output devices connected to this AudioTrack.
-    // A string OR of various output device categories, e.g. "DEVICE1|DEVICE2".
-    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    // See audio_device_t in system/media/audio/include/system/audio-base.h
-    optional string devices = 1;
-
-    // The name of the remote device attached to the device, typically available for USB or BT.
-    // This may be empty for a fixed device, or separated by "|" if more than one.
-    optional string device_names = 2;
-
-    // The amount of time spent in the device as measured by the active track in AudioFlinger.
-    optional int64 device_time_nanos = 3;
-
-    // The audio data format used for encoding.
-    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
-    optional string encoding = 4;
-
-    // The client-server buffer framecount.
-    // The framecount is generally between 960 - 48000 for PCM encoding.
-    // The framecount represents raw buffer size in bytes for non-PCM encoding.
-    // A static track (see traits) may have a very large framecount.
-    optional int32 frame_count = 5;
-
-    // The number of audio intervals (contiguous, continuous playbacks).
-    optional int32 interval_count = 6;
-
-    // The sample rate of the AudioTrack.
-    // A number generally between 8000-96000 (frames per second).
-    optional int32 sample_rate = 7;
-
-    // The audio flags used to construct the AudioTrack.
-    // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t
-    optional string flags = 8;
-
-    // The number of underruns encountered.
-    optional int32 xruns = 9;
-
-    // The santized package name of the audio client associated with the AudioTrack.
-    // See getSanitizedPackageNameAndVersionCode() in
-    // frameworks/av/services/mediametrics/MediaMetricsService.cpp
-    optional string package_name = 10;
-
-    // The latency of the last sample in the buffer in milliseconds.
-    optional float device_latency_millis = 11;
-
-    // The startup time in milliseconds from start() to sample played.
-    optional float device_startup_millis = 12;
-
-    // The average volume of the track on the device [ 0.f - 1.f ]
-    optional float device_volume = 13;
-
-    // The selected device id (nonzero if a non-default device is selected)
-    optional int32 selected_device_id = 14;
-
-    // The stream_type category for the AudioTrack.
-    // An enumeration from system/media/audio/include/system/audio-base.h audio_stream_type_t
-    optional string stream_type = 15;
-
-    // The usage for the AudioTrack.
-    // An enumeration from system/media/audio/include/system/audio-base.h audio_usage_t
-    optional string usage = 16;
-
-    // The content type of the AudioTrack.
-    // An enumeration from system/media/audio/include/system/audio-base.h audio_content_type_t
-    optional string content_type = 17;
-
-    // The caller of the AudioTrack.
-    // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    optional string caller = 18;
-
-    // The traits of the AudioTrack.
-    // A string OR of different traits, may be empty string.
-    // Only "static" is supported for R.
-    // See lookup<TRACK_TRAITS>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    optional string traits = 19;
-}
-
-/**
- * Logs the status of an audio device connection attempt.
- *
- * Logged from:
- *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
- */
-message MediametricsAudioDeviceConnectionReported {
-    // The input devices represented by this report.
-    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
-    // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    // See audio_device_t in system/media/audio/include/system/audio-base.h
-    optional string input_devices = 1;
-
-    // The output devices represented by this report.
-    // A string OR of various output device categories.
-    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
-    // See audio_device_t in system/media/audio/include/system/audio-base.h
-    optional string output_devices = 2;
-
-    // The name of the remote device attached to the device, typically available for USB or BT.
-    // This may be empty for a fixed device, or separated by "|" if more than one.
-    optional string device_names = 3;
-
-    // The result of the audio device connection.
-    // 0 indicates success: connection verified.
-    // 1 indicates unknown: connection not verified or not known if diverted properly.
-    // Other values indicate specific status.
-    // See DeviceConnectionResult in frameworks/av/services/mediametrics/AudioTypes.h
-    optional int32 result = 4;
-
-    // Average milliseconds of time to connect
-    optional float time_to_connect_millis = 5;
-
-    // Number of connections if aggregated statistics, otherwise 1.
-    optional int32 connection_count = 6;
-}
-
-/**
- * Logs: i) creation of different types of cryptographic keys in the keystore,
- * ii) operations performed using the keys,
- * iii) attestation of the keys
- * Logged from: system/security/keystore/key_event_log_handler.cpp
- */
-message KeystoreKeyEventReported {
-
-    enum Algorithm {
-        /** Asymmetric algorithms. */
-        RSA = 1;
-        // 2 removed, do not reuse.
-        EC = 3;
-        /** Block cipher algorithms */
-        AES = 32;
-        TRIPLE_DES = 33;
-        /** MAC algorithms */
-        HMAC = 128;
-    };
-    /** Algorithm associated with the key */
-    optional Algorithm algorithm = 1;
-
-    /** Size of the key */
-    optional int32 key_size = 2;
-
-    enum KeyOrigin {
-        /** Generated in keymaster.  Should not exist outside the TEE. */
-        GENERATED = 0;
-        /** Derived inside keymaster.  Likely exists off-device. */
-        DERIVED = 1;
-        /** Imported into keymaster.  Existed as cleartext in Android. */
-        IMPORTED = 2;
-        /** Keymaster did not record origin. */
-        UNKNOWN = 3;
-        /** Securely imported into Keymaster. */
-        SECURELY_IMPORTED = 4;
-    };
-    /* Logs whether the key was generated, imported, securely imported, or derived.*/
-    optional KeyOrigin key_origin = 3;
-
-    enum HardwareAuthenticatorType {
-        NONE = 0;
-        PASSWORD = 1;
-        FINGERPRINT = 2;
-        // Additional entries must be powers of 2.
-    };
-    /**
-     * What auth types does this key require? If none,
-     * then no auth required.
-     */
-    optional HardwareAuthenticatorType user_auth_type = 4;
-
-    /**
-     * If user authentication is required, is the requirement time based? If it
-     * is not time based then this field will not be used and the key is per
-     * operation. Per operation keys must be user authenticated on each usage.
-     */
-    optional int32 user_auth_key_timeout_secs = 5;
-
-    /**
-     * padding mode, digest, block_mode and purpose should ideally be repeated
-     * fields. However, since statsd does not support repeated fields in
-     * pushed atoms, they are represented using bitmaps.
-     */
-
-    /** Track which padding mode is being used.*/
-    optional int32 padding_mode_bitmap = 6;
-
-    /** Track which digest is being used. */
-    optional int32 digest_bitmap = 7;
-
-    /** Track what block mode is being used (for encryption). */
-    optional int32 block_mode_bitmap = 8;
-
-    /** Track what purpose is this key serving. */
-    optional int32 purpose_bitmap = 9;
-
-    enum EcCurve {
-        P_224 = 0;
-        P_256 = 1;
-        P_384 = 2;
-        P_521 = 3;
-    };
-    /** Which ec curve was selected if elliptic curve cryptography is in use **/
-    optional EcCurve ec_curve = 10;
-
-    enum KeyBlobUsageRequirements {
-        STANDALONE = 0;
-        REQUIRES_FILE_SYSTEM = 1;
-    };
-    /** Standalone or is a file system required */
-    optional KeyBlobUsageRequirements key_blob_usage_reqs = 11;
-
-    enum Type {
-        key_operation = 0;
-        key_creation = 1;
-        key_attestation = 2;
-    }
-    /** Key creation event, operation event or attestation event? */
-    optional Type type = 12;
-
-    /** Was the key creation, operation, or attestation successful? */
-    optional bool was_successful = 13;
-
-    /** Response code or error code */
-    optional int32 error_code = 14;
-}
-
-// Blob Committer stats
-// Keep in sync between:
-//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
-//     frameworks/base/cmds/statsd/src/atoms.proto
-message BlobCommitterProto {
-    // Committer app's uid
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Unix epoch timestamp of the commit in milliseconds
-    optional int64 commit_timestamp_millis = 2;
-
-    // Flags of what access types the committer has set for the Blob
-    optional int32 access_mode = 3;
-
-    // Number of packages that have been whitelisted for ACCESS_TYPE_WHITELIST
-    optional int32 num_whitelisted_package = 4;
-}
-
-// Blob Leasee stats
-// Keep in sync between:
-//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
-//     frameworks/base/cmds/statsd/src/atoms.proto
-message BlobLeaseeProto {
-    // Leasee app's uid
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Unix epoch timestamp for lease expiration in milliseconds
-    optional int64 lease_expiry_timestamp_millis = 2;
-}
-
-// List of Blob Committers
-// Keep in sync between:
-//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
-//     frameworks/base/cmds/statsd/src/atoms.proto
-message BlobCommitterListProto {
-    repeated BlobCommitterProto committer = 1;
-}
-
-// List of Blob Leasees
-// Keep in sync between:
-//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
-//     frameworks/base/cmds/statsd/src/atoms.proto
-message BlobLeaseeListProto {
-    repeated BlobLeaseeProto leasee = 1;
-}
-
-/**
- * Logs the current state of a Blob committed with BlobStoreManager
- *
- * Pulled from:
- *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
- */
-message BlobInfo {
-    // Id of the Blob
-    optional int64 blob_id = 1;
-
-    // Size of the Blob data
-    optional int64 size = 2;
-
-    // Unix epoch timestamp of the Blob's expiration in milliseconds
-    optional int64 expiry_timestamp_millis = 3;
-
-    // List of committers of this Blob
-    optional BlobCommitterListProto committers = 4 [(log_mode) = MODE_BYTES];
-
-    // List of leasees of this Blob
-    optional BlobLeaseeListProto leasees = 5 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs when the HDMI CEC active source changes.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
- */
-message HdmiCecActiveSourceChanged {
-    // The logical address of the active source.
-    optional android.stats.hdmi.LogicalAddress active_source_logical_address = 1;
-
-    // The physical address of the active source. Consists of four hexadecimal nibbles.
-    // Examples: 0x1234, 0x0000 (root device). 0xFFFF represents an unknown or invalid address.
-    // See section 8.7 in the HDMI 1.4b spec for details.
-    optional int32 active_source_physical_address = 2;
-
-    // The relationship between this device and the active source.
-    optional android.stats.hdmi.PathRelationship local_relationship = 3;
-}
-
-/**
- * Logs when an HDMI CEC message is sent or received.
- *
- * Logged from:
- *   frameworks/base/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
- */
-message HdmiCecMessageReported {
-    // The calling uid of the application that caused this atom to be written.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Whether a HDMI CEC message is sent from this device, to this device, or neither.
-    optional android.stats.hdmi.MessageDirection direction = 2;
-
-    // The HDMI CEC logical address of the initiator.
-    optional android.stats.hdmi.LogicalAddress initiator_logical_address = 3;
-
-    // The HDMI CEC logical address of the destination.
-    optional android.stats.hdmi.LogicalAddress destination_logical_address = 4;
-
-    // The opcode of the message. Ranges from 0x00 to 0xFF.
-    // For all values, see section "CEC 15 Message Descriptions" in the HDMI CEC 1.4b spec.
-    optional int32 opcode = 5;
-
-    // The result of attempting to send the message on its final retransmission attempt.
-    // Only applicable to outgoing messages; set to SEND_MESSAGE_RESULT_UNKNOWN otherwise.
-    optional android.stats.hdmi.SendMessageResult send_message_result = 6;
-
-    // Fields specific to <User Control Pressed> messages
-
-    // The user control command that was received.
-    optional android.stats.hdmi.UserControlPressedCommand user_control_pressed_command = 7;
-
-    // Fields specific to <Feature Abort> messages
-
-    // The opcode of the message that was feature aborted.
-    // Set to 0x100 when unknown or not applicable.
-    optional int32 feature_abort_opcode = 8;
-
-    // The reason for the feature abort.
-    optional android.stats.hdmi.FeatureAbortReason feature_abort_reason = 9;
-}
-
-/**
- * Logs when an auto rotate event occurs while smart auto rotate is enabled.
- */
-message AutoRotateReported {
-    enum Orientation {
-        UNKNOWN = 1;
-        ROTATION_0 = 2;
-        ROTATION_90 = 3;
-        ROTATION_180 = 4;
-        ROTATION_270 = 5;
-        DISABLED = 6;
-        UNAVAILABLE = 7;
-        FAILURE = 8;
-    }
-
-    // Orientation of the device when a rotation was detected.
-    optional Orientation current_orientation = 1;
-    // The orientation of the phone after rotation before going through the recommendation service.
-    optional Orientation proposed_orientation = 2;
-    // Orientation recommended by the smart autorotate service component outside of the platform. It
-    // may or may not match the proposed_orientation. Can be disabled or unavailable if the
-    // recommendation service is disabled or unavailable. Will be unknown if the service failed.
-    optional Orientation recommended_orientation = 3;
-    // Time taken to calculate the rotation recommendation.
-    optional int64 recommendation_process_duration_millis = 4;
-}
-
-/**
-  * Pushes TLS handshake counters from Conscrypt.
-  * Pulled from:
-  *   external/conscrypt/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java
-  *   external/conscrypt/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
-  */
-message TlsHandshakeReported {
-    optional bool success = 1;
-
-    optional android.stats.tls.Protocol protocol = 2;
-
-    optional android.stats.tls.CipherSuite cipher_suite = 3;
-
-    optional int32 handshake_duration_millis = 4;
-}
-
-/**
- * Logs when a TextClassifier API is invoked.
- *
- * See frameworks/base/core/java/android/view/textclassifier/TextClassifier.java
- * Logged from: external/libtextclassifier/java/
- */
-message TextClassifierApiUsageReported {
-    enum ApiType {
-        UNKNOWN_API = 0;
-        SUGGEST_SELECTION = 1;
-        CLASSIFY_TEXT = 2;
-        GENERATE_LINKS = 3;
-        DETECT_LANGUAGES = 4;
-        SUGGEST_CONVERSATION_ACTIONS = 5;
-    }
-    optional ApiType api_type = 1;
-
-    enum ResultType {
-        UNKNOWN_RESULT = 0;
-        SUCCESS = 1;
-        FAIL = 2;
-    }
-    optional ResultType result_type = 2;
-    optional int64 latency_millis = 3;
-}
-
-/**
- * Logs the current state of an application before it is killed.
- *
- * Pushed from:
- *  packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
- */
-message KilledAppStatsReported {
-    // Linux process uid for the package.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // Name of the package that was killed.
-    optional string package_name = 2;
-
-    // State of the application when it was killed.
-    enum AppState {
-        UNKNOWN_APP_STATE = 0;
-        BACKGROUND = 1;
-        FOREGROUND = 2;
-    }
-    optional AppState app_state = 3;
-
-    // System state indicating whether the system was in normal mode or garage mode.
-    enum SystemState {
-        UNKNOWN_SYSTEM_STATE = 0;
-        USER_INTERACTION_MODE = 1;
-        NO_USER_INTERACTION_MODE = 2;
-    }
-    optional SystemState system_state = 4;
-
-    // Reason for killing the application.
-    // Keep in sync between:
-    //   packages/services/Car/watchdog/server/src/ApplicationTerminator.h
-    //   frameworks/base/cmds/statsd/src/atoms.proto
-    enum KillReason {
-        UNKNOWN_KILL_REASON = 0;
-        KILLED_ON_ANR = 1;
-        KILLED_ON_IO_OVERUSE = 2;
-        KILLED_ON_MEMORY_OVERUSE = 3;
-    }
-    optional KillReason kill_reason = 5;
-
-    // Stats of the processes owned by the application when the application was killed.
-    // The process stack traces are not collected when the application was killed due to IO_OVERUSE.
-    optional ProcessStats process_stat = 6 [(log_mode) = MODE_BYTES];
-
-    // The application's I/O overuse stats logged only when the kill reason is KILLED_ON_IO_OVERUSE.
-    optional IoOveruseStats io_overuse_stats = 7 [(log_mode) = MODE_BYTES];
-}
-
-/**
- * Logs I/O overuse stats for a package.
- *
- * Keep in sync between:
- *  packages/services/Car/watchdog/server/src/proto/statsd.proto
- *  frameworks/base/cmds/statsd/src/atoms.proto
- *
- * Logged from:
- *  packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
- */
-message IoOveruseStats {
-    enum Period {
-        DAILY = 0;
-        WEEKLY = 1;
-    }
-
-    // Threshold and usage stats period.
-    optional Period period = 1;
-
-    // Threshold in-terms of write bytes defined for the package.
-    optional PerStateBytes threshold = 2;
-
-    // Number of write bytes in each state for the specified period.
-    optional PerStateBytes written_bytes = 3;
-};
-
-/**
- * Logs bytes attributed to each application and system states.
- *
- * Keep in sync between:
- *  packages/services/Car/watchdog/server/src/proto/statsd.proto
- *  frameworks/base/cmds/statsd/src/atoms.proto
- *
- * Logged from:
- *  packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
- */
-message PerStateBytes {
-    // Number of bytes attributed to the application foreground.
-    optional int64 foreground_bytes = 1;
-
-    // Number of bytes attributed to the application background.
-    optional int64 background_bytes = 2;
-
-    // Number of bytes attributed to the garage mode.
-    optional int64 garage_mode_bytes = 3;
-}
-
-/**
- * Logs each ProcessStat in ProcessStats.
- * Keep in sync between:
- *  packages/services/Car/watchdog/server/src/proto/statsd.proto
- *  frameworks/base/cmds/statsd/src/atoms.proto
- * Logged from:
- *  packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
- */
-message ProcessStats {
-    // Records the stats of the processes owned by an application.
-    repeated ProcessStat process_stat = 1;
-}
-
-/**
- * Logs a process's stats.
- * Keep in sync between:
- *  packages/services/Car/watchdog/server/src/proto/statsd.proto
- *  frameworks/base/cmds/statsd/src/atoms.proto
- * Logged from:
- *  packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
- */
-message ProcessStat {
-    // Command name of the process.
-    optional string process_name = 1;
-
-    // Process uptime.
-    optional uint64 uptime_milliseconds = 2;
-
-    // Number of major page faults caused by the process and its children.
-    optional uint64 major_page_faults = 3;
-
-    // Peak virtual memory size in kb.
-    optional uint64 vm_peak_kb = 4;
-
-    // Virtual memory size in kb.
-    optional uint64 vm_size_kb = 5;
-
-    // Peak resident set size (high water mark) in kb.
-    optional uint64 vm_hwm_kb = 6;
-
-    // Resident set size in kb.
-    optional uint64 vm_rss_kb = 7;
-}
-
-/*
- * pushes Media playback information.
- * Logged from
- *   (WIP) frameworks/av/services/mediaanalytics/playback_statsd.cpp
- */
-message MediametricsPlaybackReported {
-    optional int32 uid = 1 [(is_uid) = true];
-
-    //  Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
-    optional string playback_id = 2;
-    //  The total length of the media in milliseconds. 0 for live contents.
-    optional int64 media_duration_millis = 3;
-    //  Network, device, or mixed.
-    optional android.stats.mediametrics.StreamSourceType stream_source = 4;
-    //  Stream type. DASH, HLS, etc
-    optional android.stats.mediametrics.StreamType stream_type = 5;
-    //  Live, VOD, others
-    optional android.stats.mediametrics.PlaybackType playback_type = 6;
-    //  DRM type
-    optional android.stats.mediametrics.DrmType drm_type = 7;
-    //  Main, AD, others
-    optional android.stats.mediametrics.ContentType content_type = 8;
-    //  Player name. E.g. ExoPlayer
-    optional string player_name = 9;
-    //  Player version. E.g. 1.10.3e
-    optional string player_version = 10;
-    //  Player related experiment IDs
-    optional Experiments experiment_ids = 11 [(log_mode) = MODE_BYTES];
-    //  Number of frames played. Dropped frames included. -1 means unknown.
-    optional int32 video_frames_played = 12;
-    //  Number of frames dropped. -1 means unknown.
-    optional int32 video_frames_dropped = 13;
-    //  Number of audio underruns. -1 means unknown.
-    optional int32 audio_underrun_count = 14;
-    //  Total number of bytes read from the network
-    optional int64 network_bytes_read = 15;
-    //  Total number of bytes read from on-device sources
-    optional int64 local_bytes_read = 16;
-    //  Total transfer spent reading from the network in ms.
-    // For parallel requests, the overlapping time intervals are counted only once.
-    optional int64 network_transfer_duration_millis = 17;
-}
-
-message MediaNetworkInfoChanged {
-    //  Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
-    optional string playback_id = 1;
-    //  New network type
-    optional android.stats.mediametrics.NetworkType type = 2;
-    //  Network Start time, relative to playback creation time in millisecond.
-    //  It's in absolute time (e.g. always ticks even if the playback is paused).
-    optional int64 time_since_playback_created_millis = 3;
-}
-
-message MediaPlaybackStateChanged {
-    //  Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
-    optional string playback_id = 1;
-    //  New playback state
-    optional android.stats.mediametrics.PlaybackState playback_state = 2;
-    //  State change time, relative to playback creation time in millisecond.
-    //  It's in absolute time (e.g. always ticks even if the playback is paused).
-    optional int64 time_since_playback_created_millis = 3;
-}
-
-message MediaPlaybackErrorReported {
-    //  Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
-    optional string playback_id = 1;
-    //  A shortened call stack of the error
-    optional string exception_stack = 2;
-    //  Error code
-    optional android.stats.mediametrics.PlaybackErrorCode error_code = 3;
-    //  Sub-code of error type specified by the error code.
-    optional int32 sub_error_code = 4;
-    //  Error time, relative to playback creation time in millisecond.
-    //  It's in absolute time (e.g. always ticks even if the playback is paused).
-    optional int64 time_since_playback_created_millis = 5;
-}
-
-message MediaPlaybackTrackChanged {
-    //  Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
-    optional string playback_id = 1;
-    //  The track is on or off after the change
-    optional android.stats.mediametrics.TrackState state = 2;
-    //  The reason of the track change
-    optional android.stats.mediametrics.TrackChangeReason reason = 3;
-    //  The MIME type of the container. E.g. video/mp4
-    optional string container_mime_type = 4;
-    //  The sample MIME type of the track. E.g. video/avc
-    optional string sample_mime_type = 5;
-
-    //  Codec name
-    optional string codec_name = 6;
-    //  Bits per second. 0 means unknown.
-    optional int32 bitrate = 7;
-
-    //  Track change time, relative to playback creation time in millisecond.
-    //  It's in absolute time (e.g. always ticks even if the playback is paused).
-    optional int64 time_since_playback_created_millis = 8;
-
-    //  Track type. Audio, Video, Text
-    optional android.stats.mediametrics.TrackType type = 9;
-    //  2-letter ISO 639-1 language code.
-    optional string language = 10;
-    //  IETF BCP 47 optional language region subtag based on a two-letter country code
-    optional string language_region = 11;
-    //  Number of channels
-    optional int32 channel_count = 12;
-    //  Samples per second
-    optional int32 sample_rate = 13;
-    //  The width of the video in pixels.
-    optional int32 width = 14;
-    //  The height of the video in pixels.
-    optional int32 height = 15;
-}
-
-message Experiments {
-    // Experiment IDs sent by the player.
-    repeated int64 experiments = 1;
-}
-
-/**
- * Logs when a Wifi network scan happens.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
- */
-message WifiScanReported {
-    enum Type {
-        TYPE_UNKNOWN = 0;
-
-        // Single scan.
-        TYPE_SINGLE = 1;
-
-        // Background scan (deprecated, should not happen).
-        TYPE_BACKGROUND = 2;
-    }
-
-    enum Result {
-        RESULT_UNKNOWN = 0;
-
-        // Failed to start scan.
-        RESULT_FAILED_TO_START = 1;
-
-        // The HAL reported a scan failure after the scan was started.
-        RESULT_FAILED_TO_SCAN = 2;
-
-        // Scan succeeded.
-        RESULT_SUCCESS = 3;
-    }
-
-    enum Source {
-        SOURCE_UNKNOWN = 0;
-
-        // No work source set - not possible to determine the origin.
-        SOURCE_NO_WORK_SOURCE = 1;
-
-        // The Wifi stack.
-        SOURCE_WIFI_STACK = 2;
-
-        // GMS on behalf of some other app.
-        SOURCE_GMS = 3;
-
-        // Settings app.
-        SOURCE_SETTINGS_APP = 4;
-
-        // Other app directly.
-        SOURCE_OTHER_APP = 5;
-    }
-
-    enum Importance {
-        IMPORTANCE_UNKNOWN = 0;
-
-        // Foreground app. Corresponds to the value of
-        // ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND or less.
-        IMPORTANCE_FOREGROUND = 1;
-
-        // Foreground service. Corresponds to the value of
-        // ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
-        IMPORTANCE_FOREGROUND_SERVICE = 2;
-
-        // Everything else.
-        IMPORTANCE_BACKGROUND = 3;
-    }
-
-    // Scan type
-    optional Type type = 1;
-
-    // Outcome: success/failure
-    optional Result result = 2;
-
-    // What initiated a scan.
-    optional Source source = 3;
-
-    // Process importance of the initiator.
-    // This is only available for non-system calls.
-    optional Importance importance = 4;
-
-    // Time taken for the scan.
-    optional int32 scan_duration_millis = 5;
-
-    // Count of found networks.
-    optional int32 count_networks_found = 6;
-}
-
-/**
- * Logs when a Wifi PNO (Preferred Network Offload) scan happens.
- *
- * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
- */
-message WifiPnoScanReported {
-    enum State {
-        UNKNOWN = 0;
-
-        // Scan started.
-        STARTED = 1;
-
-        // Scan failed to start (e.g. bad request, unsupported by hardware, etc).
-        FAILED_TO_START = 2;
-
-        // Scan completed and a network was found.
-        // Note - due to implementation constraints, nothing is reported when a scan completes but
-        // doesn't find any networks.
-        FINISHED_NETWORKS_FOUND = 3;
-
-        // Scan failed.
-        FAILED = 4;
-    }
-
-    optional State state = 1;
-}
diff --git a/cmds/statsd/src/shell/shell_data.proto b/cmds/statsd/src/shell/shell_data.proto
index 236bdbd..ec41cbc 100644
--- a/cmds/statsd/src/shell/shell_data.proto
+++ b/cmds/statsd/src/shell/shell_data.proto
@@ -21,7 +21,7 @@
 option java_package = "com.android.os.statsd";
 option java_outer_classname = "ShellDataProto";
 
-import "frameworks/base/cmds/statsd/src/atoms.proto";
+import "frameworks/proto_logging/stats/atoms.proto";
 
 // The output of shell subscription, including both pulled and pushed subscriptions.
 message ShellData {
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index ddd2725..bb07963 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -21,7 +21,7 @@
 option java_package = "com.android.os";
 option java_outer_classname = "StatsLog";
 
-import "frameworks/base/cmds/statsd/src/atoms.proto";
+import "frameworks/proto_logging/stats/atoms.proto";
 
 message DimensionsValue {
   optional int32 field = 1;
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 5c170c0..bde59f4 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -16,8 +16,8 @@
 
 #include <gtest/gtest.h>
 
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
-#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h"
+#include "frameworks/proto_logging/stats/atoms.pb.h"
+#include "frameworks/proto_logging/stats/enums/stats/launcher/launcher.pb.h"
 #include "log/log_event_list.h"
 #include "stats_event.h"
 
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index 4fa4135..1ba8593 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -20,9 +20,9 @@
 
 #include <vector>
 
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
 #include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
 #include "frameworks/base/cmds/statsd/src/shell/shell_data.pb.h"
+#include "frameworks/proto_logging/stats/atoms.pb.h"
 #include "stats_event.h"
 #include "tests/metrics/metrics_test_helper.h"
 #include "tests/statsd_test_util.h"
diff --git a/core/api/current.txt b/core/api/current.txt
index 9f7f391..9cec7a6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6968,6 +6968,7 @@
     method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
     method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int);
+    method public boolean hasKeyPair(@NonNull String);
     method public boolean hasLockdownAdminConfiguredNetworks(@NonNull android.content.ComponentName);
     method public boolean installCaCert(@Nullable android.content.ComponentName, byte[]);
     method public boolean installExistingPackage(@NonNull android.content.ComponentName, String);
@@ -7343,6 +7344,7 @@
     field public static final int TAG_MEDIA_UNMOUNT = 210014; // 0x3345e
     field public static final int TAG_OS_SHUTDOWN = 210010; // 0x3345a
     field public static final int TAG_OS_STARTUP = 210009; // 0x33459
+    field public static final int TAG_PASSWORD_COMPLEXITY_REQUIRED = 210035; // 0x33473
     field public static final int TAG_PASSWORD_COMPLEXITY_SET = 210017; // 0x33461
     field public static final int TAG_PASSWORD_EXPIRATION_SET = 210016; // 0x33460
     field public static final int TAG_PASSWORD_HISTORY_LENGTH_SET = 210018; // 0x33462
@@ -30583,6 +30585,7 @@
     method public static long getMobileRxPackets();
     method public static long getMobileTxBytes();
     method public static long getMobileTxPackets();
+    method public static long getRxBytes(@NonNull String);
     method public static long getRxPackets(@NonNull String);
     method public static int getThreadStatsTag();
     method public static int getThreadStatsUid();
@@ -30590,6 +30593,7 @@
     method public static long getTotalRxPackets();
     method public static long getTotalTxBytes();
     method public static long getTotalTxPackets();
+    method public static long getTxBytes(@NonNull String);
     method public static long getTxPackets(@NonNull String);
     method public static long getUidRxBytes(int);
     method public static long getUidRxPackets(int);
@@ -40976,6 +40980,19 @@
 
 package android.security {
 
+  public final class AppUriAuthenticationPolicy implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Map<java.lang.String,java.util.Map<android.net.Uri,java.lang.String>> getAppAndUriMappings();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.security.AppUriAuthenticationPolicy> CREATOR;
+  }
+
+  public static final class AppUriAuthenticationPolicy.Builder {
+    ctor public AppUriAuthenticationPolicy.Builder();
+    method @NonNull public android.security.AppUriAuthenticationPolicy.Builder addAppAndUriMapping(@NonNull String, @NonNull android.net.Uri, @NonNull String);
+    method @NonNull public android.security.AppUriAuthenticationPolicy build();
+  }
+
   public final class AttestedKeyPair {
     ctor public AttestedKeyPair(@Nullable java.security.KeyPair, @NonNull java.util.List<java.security.cert.Certificate>);
     method @NonNull public java.util.List<java.security.cert.Certificate> getAttestationRecord();
@@ -41023,6 +41040,7 @@
     method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable String, int, @Nullable String);
     method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable android.net.Uri, @Nullable String);
     method @NonNull public static android.content.Intent createInstallIntent();
+    method @NonNull public static android.content.Intent createManageCredentialsIntent(@NonNull android.security.AppUriAuthenticationPolicy);
     method @Nullable @WorkerThread public static java.security.cert.X509Certificate[] getCertificateChain(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method @Nullable @WorkerThread public static java.security.PrivateKey getPrivateKey(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method @Deprecated public static boolean isBoundKeyAlgorithm(@NonNull String);
@@ -44553,6 +44571,7 @@
     method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 16384; // 0x4000
+    field public static final int CAPABILITY_CALL_COMPOSER = 32768; // 0x8000
     field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
     field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
@@ -45109,6 +45128,7 @@
     field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
     field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff
     field public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool";
+    field public static final String EXTRA_REBROADCAST_ON_UNLOCK = "android.telephony.extra.REBROADCAST_ON_UNLOCK";
     field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
     field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
     field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
@@ -45383,6 +45403,7 @@
   }
 
   public static final class CarrierConfigManager.Ims {
+    field public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = "ims.enable_presence_publish_bool";
     field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool";
     field public static final String KEY_PREFIX = "ims.";
     field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
@@ -46862,6 +46883,11 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int);
     method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE";
+    field public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE = "android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE";
+    field public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE = "android.telephony.action.CARRIER_SIGNAL_PCO_VALUE";
+    field public static final String ACTION_CARRIER_SIGNAL_REDIRECTED = "android.telephony.action.CARRIER_SIGNAL_REDIRECTED";
+    field public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED = "android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
+    field public static final String ACTION_CARRIER_SIGNAL_RESET = "android.telephony.action.CARRIER_SIGNAL_RESET";
     field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
     field public static final String ACTION_MULTI_SIM_CONFIG_CHANGED = "android.telephony.action.MULTI_SIM_CONFIG_CHANGED";
     field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED";
@@ -46904,16 +46930,23 @@
     field public static final int ERI_OFF = 1; // 0x1
     field public static final int ERI_ON = 0; // 0x0
     field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT";
+    field public static final String EXTRA_APN_PROTOCOL = "android.telephony.extra.APN_PROTOCOL";
+    field public static final String EXTRA_APN_TYPE = "android.telephony.extra.APN_TYPE";
     field public static final String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
     field public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
     field public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
+    field public static final String EXTRA_DATA_FAIL_CAUSE = "android.telephony.extra.DATA_FAIL_CAUSE";
+    field public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "android.telephony.extra.DEFAULT_NETWORK_AVAILABLE";
     field public static final String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
     field @Deprecated public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
     field public static final String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH";
     field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
     field public static final String EXTRA_NETWORK_COUNTRY = "android.telephony.extra.NETWORK_COUNTRY";
     field public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
+    field public static final String EXTRA_PCO_ID = "android.telephony.extra.PCO_ID";
+    field public static final String EXTRA_PCO_VALUE = "android.telephony.extra.PCO_VALUE";
     field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final String EXTRA_REDIRECTION_URL = "android.telephony.extra.REDIRECTION_URL";
     field public static final String EXTRA_SPECIFIC_CARRIER_ID = "android.telephony.extra.SPECIFIC_CARRIER_ID";
     field public static final String EXTRA_SPECIFIC_CARRIER_NAME = "android.telephony.extra.SPECIFIC_CARRIER_NAME";
     field public static final String EXTRA_STATE = "state";
@@ -50820,6 +50853,33 @@
     method public void onActionViewExpanded();
   }
 
+  public final class ContentInfo {
+    method @NonNull public android.content.ClipData getClip();
+    method @Nullable public android.os.Bundle getExtras();
+    method public int getFlags();
+    method @Nullable public android.net.Uri getLinkUri();
+    method public int getSource();
+    method @NonNull public java.util.Map<java.lang.Boolean,android.view.ContentInfo> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
+    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+    field public static final int SOURCE_APP = 0; // 0x0
+    field public static final int SOURCE_AUTOFILL = 4; // 0x4
+    field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+    field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+    field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+    field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
+  }
+
+  public static final class ContentInfo.Builder {
+    ctor public ContentInfo.Builder(@NonNull android.view.ContentInfo);
+    ctor public ContentInfo.Builder(@NonNull android.content.ClipData, int);
+    method @NonNull public android.view.ContentInfo build();
+    method @NonNull public android.view.ContentInfo.Builder setClip(@NonNull android.content.ClipData);
+    method @NonNull public android.view.ContentInfo.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.ContentInfo.Builder setFlags(int);
+    method @NonNull public android.view.ContentInfo.Builder setLinkUri(@Nullable android.net.Uri);
+    method @NonNull public android.view.ContentInfo.Builder setSource(int);
+  }
+
   public interface ContextMenu extends android.view.Menu {
     method public void clearHeader();
     method public android.view.ContextMenu setHeaderIcon(@DrawableRes int);
@@ -52035,34 +52095,7 @@
   }
 
   public interface OnReceiveContentListener {
-    method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.View, @NonNull android.view.OnReceiveContentListener.Payload);
-  }
-
-  public static final class OnReceiveContentListener.Payload {
-    method @NonNull public android.content.ClipData getClip();
-    method @Nullable public android.os.Bundle getExtras();
-    method public int getFlags();
-    method @Nullable public android.net.Uri getLinkUri();
-    method public int getSource();
-    method @NonNull public java.util.Map<java.lang.Boolean,android.view.OnReceiveContentListener.Payload> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
-    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
-    field public static final int SOURCE_APP = 0; // 0x0
-    field public static final int SOURCE_AUTOFILL = 4; // 0x4
-    field public static final int SOURCE_CLIPBOARD = 1; // 0x1
-    field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
-    field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
-    field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
-  }
-
-  public static final class OnReceiveContentListener.Payload.Builder {
-    ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.view.OnReceiveContentListener.Payload);
-    ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.content.ClipData, int);
-    method @NonNull public android.view.OnReceiveContentListener.Payload build();
-    method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setClip(@NonNull android.content.ClipData);
-    method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setExtras(@Nullable android.os.Bundle);
-    method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setFlags(int);
-    method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setLinkUri(@Nullable android.net.Uri);
-    method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setSource(int);
+    method @Nullable public android.view.ContentInfo onReceiveContent(@NonNull android.view.View, @NonNull android.view.ContentInfo);
   }
 
   public abstract class OrientationEventListener {
@@ -52813,7 +52846,7 @@
     method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
     method public void onProvideStructure(android.view.ViewStructure);
     method public void onProvideVirtualStructure(android.view.ViewStructure);
-    method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.OnReceiveContentListener.Payload);
+    method @Nullable public android.view.ContentInfo onReceiveContent(@NonNull android.view.ContentInfo);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -52839,7 +52872,7 @@
     method public boolean performHapticFeedback(int, int);
     method public boolean performLongClick();
     method public boolean performLongClick(float, float);
-    method @Nullable public android.view.OnReceiveContentListener.Payload performReceiveContent(@NonNull android.view.OnReceiveContentListener.Payload);
+    method @Nullable public android.view.ContentInfo performReceiveContent(@NonNull android.view.ContentInfo);
     method public void playSoundEffect(int);
     method public boolean post(Runnable);
     method public boolean postDelayed(Runnable, long);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0b044be..a69f456 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -228,6 +228,7 @@
     field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
     field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
     field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND";
+    field public static final String START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND";
     field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
     field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
     field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
@@ -247,7 +248,9 @@
     field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
     field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
     field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
+    field public static final String WIFI_ACCESS_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS";
     field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
+    field public static final String WIFI_UPDATE_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS";
     field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
@@ -603,7 +606,7 @@
     method public static android.app.BroadcastOptions makeBasic();
     method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
     method public void setDontSendToRestrictedApps(boolean);
-    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void setTemporaryAppWhitelistDuration(long);
+    method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
     method public android.os.Bundle toBundle();
   }
 
@@ -1764,6 +1767,7 @@
     field public static final String BACKUP_SERVICE = "backup";
     field public static final String BATTERY_STATS_SERVICE = "batterystats";
     field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
+    field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
     field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
@@ -2280,6 +2284,7 @@
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
+    field public static final int PROTECTION_FLAG_RECENTS = 33554432; // 0x2000000
     field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
     field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
@@ -6690,6 +6695,7 @@
     method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
     method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
     method public final void sendSocketKeepaliveEvent(int, int);
+    method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
     method public void unregister();
     field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
     field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
@@ -8416,6 +8422,8 @@
     field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
     field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
     field public static final String NAMESPACE_SCHEDULER = "scheduler";
+    field public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
+    field public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
     field @Deprecated public static final String NAMESPACE_STORAGE = "storage";
     field public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
     field public static final String NAMESPACE_SYSTEMUI = "systemui";
@@ -11428,6 +11436,61 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.AudioCodecAttributes> CREATOR;
   }
 
+  public interface DelegateMessageCallback {
+    method public void onMessageReceived(@NonNull android.telephony.ims.SipMessage);
+    method public void onMessageSendFailure(@NonNull String, int);
+    method public void onMessageSent(@NonNull String);
+  }
+
+  public final class DelegateRegistrationState implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteredFeatureTags();
+    method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteringFeatureTags();
+    method @NonNull public java.util.Set<java.lang.String> getRegisteredFeatureTags();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.DelegateRegistrationState> CREATOR;
+    field public static final int DEREGISTERED_REASON_NOT_PROVISIONED = 1; // 0x1
+    field public static final int DEREGISTERED_REASON_NOT_REGISTERED = 2; // 0x2
+    field public static final int DEREGISTERED_REASON_UNKNOWN = 0; // 0x0
+    field public static final int DEREGISTERING_REASON_DESTROY_PENDING = 6; // 0x6
+    field public static final int DEREGISTERING_REASON_FEATURE_TAGS_CHANGING = 5; // 0x5
+    field public static final int DEREGISTERING_REASON_PDN_CHANGE = 3; // 0x3
+    field public static final int DEREGISTERING_REASON_PROVISIONING_CHANGE = 4; // 0x4
+  }
+
+  public static final class DelegateRegistrationState.Builder {
+    ctor public DelegateRegistrationState.Builder();
+    method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addDeregisteredFeatureTag(@NonNull String, int);
+    method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addDeregisteringFeatureTag(@NonNull String, int);
+    method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTag(@NonNull String);
+    method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTags(@NonNull java.util.Set<java.lang.String>);
+    method @NonNull public android.telephony.ims.DelegateRegistrationState build();
+  }
+
+  public final class DelegateRequest implements android.os.Parcelable {
+    ctor public DelegateRequest(@NonNull java.util.Set<java.lang.String>);
+    method public int describeContents();
+    method @NonNull public java.util.Set<java.lang.String> getFeatureTags();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.DelegateRequest> CREATOR;
+  }
+
+  public interface DelegateStateCallback {
+    method public void onCreated(@NonNull android.telephony.ims.stub.SipDelegate, @Nullable java.util.Set<android.telephony.ims.FeatureTagState>);
+    method public void onDestroyed(int);
+    method public void onFeatureTagRegistrationChanged(@NonNull android.telephony.ims.DelegateRegistrationState);
+    method public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+  }
+
+  public final class FeatureTagState implements android.os.Parcelable {
+    ctor public FeatureTagState(@NonNull String, int);
+    method public int describeContents();
+    method @NonNull public String getFeatureTag();
+    method public int getState();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.FeatureTagState> CREATOR;
+  }
+
   public final class ImsCallForwardInfo implements android.os.Parcelable {
     ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
     method public int describeContents();
@@ -11464,6 +11527,7 @@
     method public boolean getCallExtraBoolean(String, boolean);
     method public int getCallExtraInt(String);
     method public int getCallExtraInt(String, int);
+    method @Nullable public <T extends android.os.Parcelable> T getCallExtraParcelable(@Nullable String);
     method public android.os.Bundle getCallExtras();
     method public int getCallType();
     method public static int getCallTypeFromVideoState(int);
@@ -11486,6 +11550,7 @@
     method public void setCallExtra(String, String);
     method public void setCallExtraBoolean(String, boolean);
     method public void setCallExtraInt(String, int);
+    method public void setCallExtraParcelable(@NonNull String, @NonNull android.os.Parcelable);
     method public void setCallRestrictCause(int);
     method public void setCallerNumberVerificationStatus(int);
     method public void setEmergencyCallRouting(int);
@@ -11520,6 +11585,7 @@
     field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE";
     field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
     field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+    field public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT";
     field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
     field public static final String EXTRA_CNA = "cna";
     field public static final String EXTRA_CNAP = "cnap";
@@ -11529,8 +11595,11 @@
     field public static final String EXTRA_EMERGENCY_CALL = "e_call";
     field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER";
     field public static final String EXTRA_IS_CALL_PULL = "CallPull";
+    field public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION";
     field public static final String EXTRA_OI = "oi";
     field public static final String EXTRA_OIR = "oir";
+    field public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
+    field public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY";
     field public static final String EXTRA_REMOTE_URI = "remote_uri";
     field public static final String EXTRA_USSD = "ussd";
     field public static final int OIR_DEFAULT = 0; // 0x0
@@ -11538,6 +11607,8 @@
     field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1
     field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3
+    field public static final int PRIORITY_NORMAL = 0; // 0x0
+    field public static final int PRIORITY_URGENT = 1; // 0x1
     field public static final int SERVICE_TYPE_EMERGENCY = 2; // 0x2
     field public static final int SERVICE_TYPE_NONE = 0; // 0x0
     field public static final int SERVICE_TYPE_NORMAL = 1; // 0x1
@@ -11948,8 +12019,107 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RtpHeaderExtensionType> CREATOR;
   }
 
+  public interface SipDelegateConnection {
+    method public void notifyMessageReceiveError(@NonNull String, int);
+    method public void notifyMessageReceived(@NonNull String);
+    method public void sendMessage(@NonNull android.telephony.ims.SipMessage, long);
+  }
+
+  public final class SipDelegateImsConfiguration implements android.os.Parcelable {
+    method public boolean containsKey(@NonNull String);
+    method @NonNull public android.os.PersistableBundle copyBundle();
+    method public int describeContents();
+    method public boolean getBoolean(@NonNull String, boolean);
+    method public int getInt(@NonNull String, int);
+    method @Nullable public String getString(@NonNull String);
+    method public long getVersion();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
+    field public static final String IPTYPE_IPV4 = "IPV4";
+    field public static final String IPTYPE_IPV6 = "IPV6";
+    field public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
+    field public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
+    field public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
+    field public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
+    field public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
+    field public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
+    field public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
+    field public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
+    field public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
+    field public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
+    field public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
+    field public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
+    field public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
+    field public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
+    field public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
+    field public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
+    field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
+    field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
+    field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
+    field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
+    field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
+    field public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
+    field public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
+    field public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
+    field public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
+    field public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
+    field public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
+    field public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
+    field public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
+    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
+    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
+    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
+    field public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
+    field public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
+    field public static final String SIP_TRANSPORT_TCP = "TCP";
+    field public static final String SIP_TRANSPORT_UDP = "UDP";
+  }
+
+  public static final class SipDelegateImsConfiguration.Builder {
+    ctor public SipDelegateImsConfiguration.Builder(int);
+    ctor public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
+    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
+    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
+    method @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
+  }
+
   public class SipDelegateManager {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException;
+    field public static final int DENIED_REASON_INVALID = 4; // 0x4
+    field public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1; // 0x1
+    field public static final int DENIED_REASON_NOT_ALLOWED = 2; // 0x2
+    field public static final int DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED = 3; // 0x3
+    field public static final int DENIED_REASON_UNKNOWN = 0; // 0x0
+    field public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2; // 0x2
+    field public static final int MESSAGE_FAILURE_REASON_DELEGATE_DEAD = 1; // 0x1
+    field public static final int MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION = 11; // 0xb
+    field public static final int MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT = 5; // 0x5
+    field public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6; // 0x6
+    field public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4; // 0x4
+    field public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3; // 0x3
+    field public static final int MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE = 8; // 0x8
+    field public static final int MESSAGE_FAILURE_REASON_NOT_REGISTERED = 9; // 0x9
+    field public static final int MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION = 10; // 0xa
+    field public static final int MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE = 7; // 0x7
+    field public static final int MESSAGE_FAILURE_REASON_UNKNOWN = 0; // 0x0
+    field public static final int SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP = 2; // 0x2
+    field public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD = 1; // 0x1
+    field public static final int SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN = 4; // 0x4
+    field public static final int SIP_DELEGATE_DESTROY_REASON_UNKNOWN = 0; // 0x0
+    field public static final int SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS = 3; // 0x3
+  }
+
+  public final class SipMessage implements android.os.Parcelable {
+    ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]);
+    method public int describeContents();
+    method @NonNull public byte[] getContent();
+    method @NonNull public String getHeaderSection();
+    method @NonNull public String getStartLine();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
   }
 
 }
@@ -12043,6 +12213,19 @@
 
 package android.telephony.ims.stub {
 
+  public interface DelegateConnectionMessageCallback {
+    method public void onMessageReceived(@NonNull android.telephony.ims.SipMessage);
+    method public void onMessageSendFailure(@NonNull String, int);
+    method public void onMessageSent(@NonNull String);
+  }
+
+  public interface DelegateConnectionStateCallback {
+    method public void onCreated(@NonNull android.telephony.ims.SipDelegateConnection);
+    method public void onDestroyed(int);
+    method public void onFeatureTagStatusChanged(@NonNull android.telephony.ims.DelegateRegistrationState, @NonNull java.util.Set<android.telephony.ims.FeatureTagState>);
+    method public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+  }
+
   public class ImsCallSessionImplBase implements java.lang.AutoCloseable {
     ctor public ImsCallSessionImplBase();
     method public void accept(int, android.telephony.ims.ImsStreamMediaProfile);
@@ -12203,8 +12386,17 @@
     method public int updateColr(int);
   }
 
+  public interface SipDelegate {
+    method public void closeDialog(@NonNull String);
+    method public void notifyMessageReceiveError(@NonNull String, int);
+    method public void notifyMessageReceived(@NonNull String);
+    method public void sendMessage(@NonNull android.telephony.ims.SipMessage, long);
+  }
+
   public class SipTransportImplBase {
     ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor);
+    method public void createSipDelegate(int, @NonNull android.telephony.ims.DelegateRequest, @NonNull android.telephony.ims.DelegateStateCallback, @NonNull android.telephony.ims.DelegateMessageCallback);
+    method public void destroySipDelegate(@NonNull android.telephony.ims.stub.SipDelegate, int);
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 52a79ba..e392ed7 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -7,6 +7,7 @@
     field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
     field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
     field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
+    field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
     field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
     field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
@@ -832,6 +833,14 @@
 
 }
 
+package android.inputmethodservice {
+
+  public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService {
+    field public static final long FINISH_INPUT_NO_FALLBACK_CONNECTION = 156215187L; // 0x94fa793L
+  }
+
+}
+
 package android.location {
 
   public final class GnssClock implements android.os.Parcelable {
@@ -1491,7 +1500,6 @@
     field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
     field public static final String HIDDEN_API_POLICY = "hidden_api_policy";
     field public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs";
-    field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
     field public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist";
     field public static final String LOW_POWER_MODE = "low_power";
     field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
@@ -2082,12 +2090,15 @@
   }
 
   public interface WindowManager extends android.view.ViewManager {
+    method public default int getDisplayImePolicy(int);
     method public default void holdLock(android.os.IBinder, int);
-    method public default void setShouldShowIme(int, boolean);
+    method public default void setDisplayImePolicy(int, int);
     method public default void setShouldShowSystemDecors(int, boolean);
     method public default void setShouldShowWithInsecureKeyguard(int, boolean);
-    method public default boolean shouldShowIme(int);
     method public default boolean shouldShowSystemDecors(int);
+    field public static final int DISPLAY_IME_POLICY_FALLBACK_DISPLAY = 1; // 0x1
+    field public static final int DISPLAY_IME_POLICY_HIDE = 2; // 0x2
+    field public static final int DISPLAY_IME_POLICY_LOCAL = 0; // 0x0
   }
 
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java
index fc93f03..08861d4 100644
--- a/core/java/android/annotation/RequiresFeature.java
+++ b/core/java/android/annotation/RequiresFeature.java
@@ -30,7 +30,6 @@
  * Denotes that the annotated element requires one or more device features. This
  * is used to auto-generate documentation.
  *
- * @see PackageManager#hasSystemFeature(String)
  * @hide
  */
 @Retention(SOURCE)
@@ -38,8 +37,16 @@
 public @interface RequiresFeature {
     /**
      * The name of the device feature that is required.
-     *
-     * @see PackageManager#hasSystemFeature(String)
      */
     String value();
+
+    /**
+     * Defines the name of the method that should be called to check whether the feature is
+     * available, using the same signature format as javadoc. The feature checking method can have
+     * multiple parameters, but the feature name parameter must be of type String and must also be
+     * the first String-type parameter.
+     * <p>
+     * By default, the enforcement is {@link PackageManager#hasSystemFeature(String)}.
+     */
+    String enforcement() default("android.content.pm.PackageManager#hasSystemFeature");
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index fc95718..5ee5597 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2590,7 +2590,7 @@
     protected void onStop() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
-        mActivityTransitionState.onStop();
+        mActivityTransitionState.onStop(this);
         dispatchActivityStopped();
         mTranslucentCallback = null;
         mCalled = true;
@@ -5189,8 +5189,8 @@
      * result callbacks including {@link #onRequestPermissionsResult(int, String[], int[])}.
      * </p>
      * <p>
-     * The <a href="https://github.com/googlesamples/android-RuntimePermissions">
-     * RuntimePermissions</a> sample app demonstrates how to use this method to
+     * The <a href="https://github.com/android/permissions-samples">
+     * RuntimePermissions</a> sample apps demonstrate how to use this method to
      * request permissions at run time.
      * </p>
      *
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5537edb..e3048df 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1854,16 +1854,12 @@
      * the recent tasks.
      */
     @Deprecated
-    public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags)
-            throws SecurityException {
-        try {
-            if (maxNum < 0) {
-                throw new IllegalArgumentException("The requested number of tasks should be >= 0");
-            }
-            return getTaskService().getRecentTasks(maxNum, flags, mContext.getUserId()).getList();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+    public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags) throws SecurityException {
+        if (maxNum < 0) {
+            throw new IllegalArgumentException("The requested number of tasks should be >= 0");
         }
+        return ActivityTaskManager.getInstance().getRecentTasks(
+                maxNum, flags, mContext.getUserId());
     }
 
     /**
@@ -2084,11 +2080,7 @@
     @Deprecated
     public List<RunningTaskInfo> getRunningTasks(int maxNum)
             throws SecurityException {
-        try {
-            return getTaskService().getTasks(maxNum);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return ActivityTaskManager.getInstance().getTasks(maxNum);
     }
 
     /**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index ef146b1..0b0781e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -27,6 +27,8 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
+import android.app.ExitTransitionCoordinator.ActivityExitTransitionCallbacks;
+import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -44,8 +46,6 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
-import android.transition.Transition;
-import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
 import android.util.Pair;
 import android.util.Slog;
@@ -806,8 +806,11 @@
     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
             Pair<View, String>... sharedElements) {
         ActivityOptions opts = new ActivityOptions();
-        makeSceneTransitionAnimation(activity, activity.getWindow(), opts,
-                activity.mExitTransitionListener, sharedElements);
+        ExitTransitionCoordinator exit = makeSceneTransitionAnimation(
+                new ActivityExitTransitionCallbacks(activity), activity.mExitTransitionListener,
+                activity.getWindow(), opts, sharedElements);
+        opts.mExitCoordinatorIndex =
+                activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
         return opts;
     }
 
@@ -823,25 +826,19 @@
      * @hide
      */
     @SafeVarargs
-    public static ActivityOptions startSharedElementAnimation(Window window,
+    public static Pair<ActivityOptions, ExitTransitionCoordinator> startSharedElementAnimation(
+            Window window, ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback,
             Pair<View, String>... sharedElements) {
         ActivityOptions opts = new ActivityOptions();
-        final View decorView = window.getDecorView();
-        if (decorView == null) {
-            return opts;
-        }
-        final ExitTransitionCoordinator exit =
-                makeSceneTransitionAnimation(null, window, opts, null, sharedElements);
-        if (exit != null) {
-            HideWindowListener listener = new HideWindowListener(window, exit);
-            exit.setHideSharedElementsCallback(listener);
-            exit.startExit();
-        }
-        return opts;
+        ExitTransitionCoordinator exit = makeSceneTransitionAnimation(
+                exitCallbacks, callback, window, opts, sharedElements);
+        opts.mExitCoordinatorIndex = -1;
+        return Pair.create(opts, exit);
     }
 
     /**
-     * This method should be called when the {@link #startSharedElementAnimation(Window, Pair[])}
+     * This method should be called when the
+     * {@link #startSharedElementAnimation(Window, ExitTransitionCallbacks, Pair[])}
      * animation must be stopped and the Views reset. This can happen if there was an error
      * from startActivity or a springboard activity and the animation should stop and reset.
      *
@@ -864,9 +861,9 @@
         }
     }
 
-    static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window,
-            ActivityOptions opts, SharedElementCallback callback,
-            Pair<View, String>[] sharedElements) {
+    static ExitTransitionCoordinator makeSceneTransitionAnimation(
+            ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback, Window window,
+            ActivityOptions opts, Pair<View, String>[] sharedElements) {
         if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
             opts.mAnimationType = ANIM_DEFAULT;
             return null;
@@ -892,17 +889,11 @@
             }
         }
 
-        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window,
+        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(exitCallbacks, window,
                 callback, names, names, views, false);
         opts.mTransitionReceiver = exit;
         opts.mSharedElementNames = names;
-        opts.mIsReturning = (activity == null);
-        if (activity == null) {
-            opts.mExitCoordinatorIndex = -1;
-        } else {
-            opts.mExitCoordinatorIndex =
-                    activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
-        }
+        opts.mIsReturning = false;
         return exit;
     }
 
@@ -928,8 +919,12 @@
         opts.mIsReturning = true;
         opts.mResultCode = resultCode;
         opts.mResultData = resultData;
-        opts.mExitCoordinatorIndex =
-                activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
+        if (activity == null) {
+            opts.mExitCoordinatorIndex = -1;
+        } else {
+            opts.mExitCoordinatorIndex =
+                    activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
+        }
         return opts;
     }
 
@@ -1868,67 +1863,6 @@
                 + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
     }
 
-    private static class HideWindowListener extends TransitionListenerAdapter
-        implements ExitTransitionCoordinator.HideSharedElementsCallback {
-        private final Window mWindow;
-        private final ExitTransitionCoordinator mExit;
-        private final boolean mWaitingForTransition;
-        private boolean mTransitionEnded;
-        private boolean mSharedElementHidden;
-        private ArrayList<View> mSharedElements;
-
-        public HideWindowListener(Window window, ExitTransitionCoordinator exit) {
-            mWindow = window;
-            mExit = exit;
-            mSharedElements = new ArrayList<>(exit.mSharedElements);
-            Transition transition = mWindow.getExitTransition();
-            if (transition != null) {
-                transition.addListener(this);
-                mWaitingForTransition = true;
-            } else {
-                mWaitingForTransition = false;
-            }
-            View decorView = mWindow.getDecorView();
-            if (decorView != null) {
-                if (decorView.getTag(com.android.internal.R.id.cross_task_transition) != null) {
-                    throw new IllegalStateException(
-                            "Cannot start a transition while one is running");
-                }
-                decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, exit);
-            }
-        }
-
-        @Override
-        public void onTransitionEnd(Transition transition) {
-            mTransitionEnded = true;
-            hideWhenDone();
-            transition.removeListener(this);
-        }
-
-        @Override
-        public void hideSharedElements() {
-            mSharedElementHidden = true;
-            hideWhenDone();
-        }
-
-        private void hideWhenDone() {
-            if (mSharedElementHidden && (!mWaitingForTransition || mTransitionEnded)) {
-                mExit.resetViews();
-                int numSharedElements = mSharedElements.size();
-                for (int i = 0; i < numSharedElements; i++) {
-                    View view = mSharedElements.get(i);
-                    view.requestLayout();
-                }
-                View decorView = mWindow.getDecorView();
-                if (decorView != null) {
-                    decorView.setTagInternal(
-                            com.android.internal.R.id.cross_task_transition, null);
-                    decorView.setVisibility(View.GONE);
-                }
-            }
-        }
-    }
-
     /**
      * The information about the source of activity launch. E.g. describe an activity is launched
      * from launcher by receiving a motion event with a timestamp.
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index c7b9089..03c1a01 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -27,7 +27,6 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Build;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -35,6 +34,7 @@
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
 import android.util.Singleton;
+import android.view.RemoteAnimationDefinition;
 
 import java.util.List;
 
@@ -147,7 +147,20 @@
 
     private static int sMaxRecentTasks = -1;
 
-    ActivityTaskManager(Context context, Handler handler) {
+    private static final Singleton<ActivityTaskManager> sInstance =
+            new Singleton<ActivityTaskManager>() {
+                @Override
+                protected ActivityTaskManager create() {
+                    return new ActivityTaskManager();
+                }
+            };
+
+    private ActivityTaskManager() {
+    }
+
+    /** @hide */
+    public static ActivityTaskManager getInstance() {
+        return sInstance.get();
     }
 
     /** @hide */
@@ -444,6 +457,98 @@
     }
 
     /**
+     * @return List of running tasks.
+     * @hide
+     */
+    public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
+        return getTasks(maxNum, false /* filterForVisibleRecents */);
+    }
+
+    /**
+     * @return List of running tasks that can be filtered by visibility in recents.
+     * @hide
+     */
+    public List<ActivityManager.RunningTaskInfo> getTasks(
+            int maxNum, boolean filterOnlyVisibleRecents) {
+        try {
+            return getService().getTasks(maxNum, filterOnlyVisibleRecents);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @return List of recent tasks.
+     * @hide
+     */
+    public List<ActivityManager.RecentTaskInfo> getRecentTasks(
+            int maxNum, int flags, int userId) {
+        try {
+            return getService().getRecentTasks(maxNum, flags, userId).getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public void registerTaskStackListener(TaskStackListener listener) {
+        try {
+            getService().registerTaskStackListener(listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public void unregisterTaskStackListener(TaskStackListener listener) {
+        try {
+            getService().unregisterTaskStackListener(listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public Rect getTaskBounds(int taskId) {
+        try {
+            return getService().getTaskBounds(taskId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers remote animations for a display.
+     * @hide
+     */
+    public void registerRemoteAnimationsForDisplay(
+            int displayId, RemoteAnimationDefinition definition) {
+        try {
+            getService().registerRemoteAnimationsForDisplay(displayId, definition);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public boolean isInLockTaskMode() {
+        try {
+            return getService().isInLockTaskMode();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public boolean removeTask(int taskId) {
+        try {
+            return getService().removeTask(taskId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Information you can retrieve about a root task in the system.
      * @hide
      */
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 5c4125e..6261950 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -247,14 +247,14 @@
         mEnterActivityOptions = null;
     }
 
-    public void onStop() {
+    public void onStop(Activity activity) {
         restoreExitedViews();
         if (mEnterTransitionCoordinator != null) {
             mEnterTransitionCoordinator.stop();
             mEnterTransitionCoordinator = null;
         }
         if (mReturnExitCoordinator != null) {
-            mReturnExitCoordinator.stop();
+            mReturnExitCoordinator.stop(activity);
             mReturnExitCoordinator = null;
         }
     }
@@ -331,7 +331,8 @@
                     }
                 }
 
-                mReturnExitCoordinator = new ExitTransitionCoordinator(activity,
+                mReturnExitCoordinator = new ExitTransitionCoordinator(
+                        new ExitTransitionCoordinator.ActivityExitTransitionCallbacks(activity),
                         activity.getWindow(), activity.mEnterTransitionListener, pendingExitNames,
                         null, null, true);
                 if (enterViewsTransition != null && decor != null) {
@@ -341,12 +342,11 @@
                     final ViewGroup finalDecor = decor;
                     OneShotPreDrawListener.add(decor, () -> {
                         if (mReturnExitCoordinator != null) {
-                            mReturnExitCoordinator.startExit(activity.mResultCode,
-                                    activity.mResultData);
+                            mReturnExitCoordinator.startExit(activity);
                         }
                     });
                 } else {
-                    mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData);
+                    mReturnExitCoordinator.startExit(activity);
                 }
             }
             return true;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index cdfe41e..4dd6a7e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -358,7 +358,7 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, prefix = { "MODE_" }, value = {
+    @IntDef(prefix = { "MODE_" }, value = {
             MODE_ALLOWED,
             MODE_IGNORED,
             MODE_ERRORED,
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 03dca30..298c455 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -90,7 +90,9 @@
      * power allowlist when this broadcast is being delivered to it.
      * @param duration The duration in milliseconds; 0 means to not place on allowlist.
      */
-    @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+    @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+            android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+            android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
     public void setTemporaryAppWhitelistDuration(long duration) {
         mTemporaryAppWhitelistDuration = duration;
     }
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 68824cd..9fdff59 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -18,6 +18,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.annotation.NonNull;
 import android.app.SharedElementCallback.OnSharedElementsReadyListener;
 import android.content.Intent;
 import android.graphics.Color;
@@ -45,15 +46,17 @@
  * This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation
  * to govern the exit of the Scene and the shared elements when calling an Activity as well as
  * the reentry of the Scene when coming back from the called Activity.
+ *
+ * @hide
  */
-class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
+public class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
     private static final String TAG = "ExitTransitionCoordinator";
     static long sMaxWaitMillis = 1000;
 
     private Bundle mSharedElementBundle;
     private boolean mExitNotified;
     private boolean mSharedElementNotified;
-    private Activity mActivity;
+    private ExitTransitionCallbacks mExitCallbacks;
     private boolean mIsBackgroundReady;
     private boolean mIsCanceled;
     private Handler mHandler;
@@ -62,20 +65,15 @@
     private Bundle mExitSharedElementBundle;
     private boolean mIsExitStarted;
     private boolean mSharedElementsHidden;
-    private HideSharedElementsCallback mHideSharedElementsCallback;
 
-    public ExitTransitionCoordinator(Activity activity, Window window,
-            SharedElementCallback listener, ArrayList<String> names,
+    public ExitTransitionCoordinator(ExitTransitionCallbacks exitCallbacks,
+            Window window, SharedElementCallback listener, ArrayList<String> names,
             ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
         super(window, names, listener, isReturning);
         viewsReady(mapSharedElements(accepted, mapped));
         stripOffscreenViews();
         mIsBackgroundReady = !isReturning;
-        mActivity = activity;
-    }
-
-    void setHideSharedElementsCallback(HideSharedElementsCallback callback) {
-        mHideSharedElementsCallback = callback;
+        mExitCallbacks = exitCallbacks;
     }
 
     @Override
@@ -190,8 +188,8 @@
 
     private void hideSharedElements() {
         moveSharedElementsFromOverlay();
-        if (mHideSharedElementsCallback != null) {
-            mHideSharedElementsCallback.hideSharedElements();
+        if (mExitCallbacks != null) {
+            mExitCallbacks.hideSharedElements();
         }
         if (!mIsHidden) {
             hideViews(mSharedElements);
@@ -210,20 +208,16 @@
                 decorView.suppressLayout(true);
             }
             moveSharedElementsToOverlay();
-            startTransition(new Runnable() {
-                @Override
-                public void run() {
-                    if (mActivity != null) {
-                        beginTransitions();
-                    } else {
-                        startExitTransition();
-                    }
-                }
-            });
+            startTransition(this::beginTransitions);
         }
     }
 
-    public void startExit(int resultCode, Intent data) {
+    /**
+     * Starts the exit animation and sends back the activity result
+     */
+    public void startExit(Activity activity) {
+        int resultCode = activity.mResultCode;
+        Intent data = activity.mResultData;
         if (!mIsExitStarted) {
             mIsExitStarted = true;
             pauseInput();
@@ -247,9 +241,9 @@
                     .getApplicationInfo().targetSdkVersion >= VERSION_CODES.M;
             ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames :
                     mAllSharedElementNames;
-            ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
+            ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, this,
                     sharedElementNames, resultCode, data);
-            mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+            activity.convertToTranslucent(new Activity.TranslucentConversionListener() {
                 @Override
                 public void onTranslucentConversionComplete(boolean drawComplete) {
                     if (!mIsCanceled) {
@@ -257,21 +251,19 @@
                     }
                 }
             }, options);
-            startTransition(new Runnable() {
-                @Override
-                public void run() {
-                    startExitTransition();
-                }
-            });
+            startTransition(this::startExitTransition);
         }
     }
 
-    public void stop() {
-        if (mIsReturning && mActivity != null) {
+    /**
+     * Called from {@link Activity#onStop()}
+     */
+    public void stop(Activity activity) {
+        if (mIsReturning && mExitCallbacks != null) {
             // Override the previous ActivityOptions. We don't want the
             // activity to have options since we're essentially canceling the
             // transition and finishing right now.
-            mActivity.convertToTranslucent(null, null);
+            activity.convertToTranslucent(null, null);
             finish();
         }
     }
@@ -434,7 +426,7 @@
                 mSharedElementNotified = true;
                 delayCancel();
 
-                if (!mActivity.isTopOfTask()) {
+                if (mExitCallbacks.isReturnTransitionAllowed()) {
                     mResultReceiver.send(MSG_ALLOW_RETURN_TRANSITION, null);
                 }
 
@@ -474,22 +466,20 @@
     }
 
     private void finishIfNecessary() {
-        if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
-                mSharedElementsHidden)) {
+        if (mIsReturning && mExitNotified && mExitCallbacks != null && (mSharedElements.isEmpty()
+                || mSharedElementsHidden)) {
             finish();
         }
         if (!mIsReturning && mExitNotified) {
-            mActivity = null; // don't need it anymore
+            mExitCallbacks = null; // don't need it anymore
         }
     }
 
     private void finish() {
         stopCancel();
-        if (mActivity != null) {
-            mActivity.mActivityTransitionState.clear();
-            mActivity.finish();
-            mActivity.overridePendingTransition(0, 0);
-            mActivity = null;
+        if (mExitCallbacks != null) {
+            mExitCallbacks.onFinish();
+            mExitCallbacks = null;
         }
         // Clear the state so that we can't hold any references accidentally and leak memory.
         clearState();
@@ -529,7 +519,49 @@
         }
     }
 
-    interface HideSharedElementsCallback {
-        void hideSharedElements();
+    /**
+     * @hide
+     */
+    public interface ExitTransitionCallbacks {
+
+        /**
+         * Returns true if reverse exit animation is supported
+         */
+        boolean isReturnTransitionAllowed();
+
+        /**
+         * Called then the transition finishes
+         */
+        void onFinish();
+
+        /**
+         * Optional callback when the transition is hiding elements in the source surface
+         */
+        default void hideSharedElements() { };
+    }
+
+    /**
+     * @hide
+     */
+    public static class ActivityExitTransitionCallbacks implements ExitTransitionCallbacks {
+
+        @NonNull
+        final Activity mActivity;
+
+        ActivityExitTransitionCallbacks(@NonNull Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public boolean isReturnTransitionAllowed() {
+            return !mActivity.isTopOfTask();
+        }
+
+        @Override
+        public void onFinish() {
+            mActivity.mActivityTransitionState.clear();
+            mActivity.finish();
+            mActivity.overridePendingTransition(0, 0);
+        }
     }
 }
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index bd5913e..ab48bae 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -83,6 +83,15 @@
  *
  * {@hide}
  */
+// TODO(b/174040395): Make this interface private to ActivityTaskManager.java and have external
+// caller go through that call instead. This would help us better separate and control the API
+// surface exposed.
+// TODO(b/174041144): Move callback methods from Activity (Things that take param 'IBinder token')
+// to a separate interface that is only available to the Activity.
+// TODO(b/174041603): Create a builder interface for things like startActivityXXX(...) to reduce
+// interface duplication.
+// TODO(b/174040691): Clean-up/remove all obsolete or unused interfaces like things that should be
+// going through task organizer now.
 interface IActivityTaskManager {
     int startActivity(in IApplicationThread caller, in String callingPackage,
             in String callingFeatureId, in Intent intent, in String resolvedType,
@@ -154,9 +163,7 @@
     void setFocusedTask(int taskId);
     boolean removeTask(int taskId);
     void removeAllVisibleRecentTasks();
-    List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
-    List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
-            boolean filterOnlyVisibleRecents);
+    List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, boolean filterOnlyVisibleRecents);
     boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
     boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
             in Intent resultData);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2bf5368..d5977e7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -30,6 +30,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Px;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -4873,6 +4874,7 @@
             // Small icon doesn't need to be reset, as it's always set. Resetting would prevent
             // re-using the drawable when the notification is updated.
             contentView.setBoolean(R.id.expand_button, "setExpanded", false);
+            contentView.setViewVisibility(R.id.app_name_text, View.GONE);
             contentView.setTextViewText(R.id.app_name_text, null);
             contentView.setViewVisibility(R.id.chronometer, View.GONE);
             contentView.setViewVisibility(R.id.header_text, View.GONE);
@@ -4901,7 +4903,7 @@
             bindNotificationHeader(contentView, p);
             bindLargeIconAndApplyMargin(contentView, p, result);
             boolean showProgress = handleProgressBar(contentView, ex, p);
-            if (p.title != null && p.title.length() > 0 && !p.mHasCustomContent) {
+            if (p.hasTitle()) {
                 contentView.setViewVisibility(R.id.title, View.VISIBLE);
                 contentView.setTextViewText(R.id.title, processTextSpans(p.title));
                 setTextViewColorPrimary(contentView, R.id.title, p);
@@ -4909,7 +4911,7 @@
                         ? ViewGroup.LayoutParams.WRAP_CONTENT
                         : ViewGroup.LayoutParams.MATCH_PARENT);
             }
-            if (p.text != null) {
+            if (p.text != null && p.text.length() != 0) {
                 int textId = showProgress ? com.android.internal.R.id.text_line_1
                         : com.android.internal.R.id.text;
                 contentView.setTextViewText(textId, processTextSpans(p.text));
@@ -5105,33 +5107,29 @@
             if (result == null) {
                 result = new TemplateBindResult();
             }
-            boolean largeIconShown = bindLargeIcon(contentView, p);
+            final boolean largeIconShown = bindLargeIcon(contentView, p);
             calculateLargeIconMarginEnd(largeIconShown, result);
             if (p.mHeaderless) {
                 // views in the headerless (collapsed) state
-                contentView.setViewLayoutMarginEnd(R.id.notification_standard_view_column,
-                        result.getHeadingExtraMarginEnd());
+                result.mHeadingExtraMarginSet.applyToView(contentView,
+                        R.id.notification_headerless_view_column);
             } else {
                 // views in states with a header (big states)
-                contentView.setInt(R.id.notification_header, "setTopLineExtraMarginEnd",
-                        result.getHeadingExtraMarginEnd());
-                contentView.setViewLayoutMarginEnd(R.id.line1, result.getTitleMarginEnd());
+                result.mHeadingExtraMarginSet.applyToView(contentView, R.id.notification_header);
+                result.mTitleMarginSet.applyToView(contentView, R.id.line1);
             }
         }
 
         private void calculateLargeIconMarginEnd(boolean largeIconShown,
                 @NonNull TemplateBindResult result) {
-            int contentMargin = mContext.getResources().getDimensionPixelSize(
+            final Resources resources = mContext.getResources();
+            final int contentMargin = resources.getDimensionPixelOffset(
                     R.dimen.notification_content_margin_end);
-            int expanderSize = mContext.getResources().getDimensionPixelSize(
+            final int expanderSize = resources.getDimensionPixelSize(
                     R.dimen.notification_header_expand_icon_size) - contentMargin;
-            int extraMarginEnd = 0;
-            if (largeIconShown) {
-                int iconSize = mContext.getResources().getDimensionPixelSize(
-                        R.dimen.notification_right_icon_size);
-                extraMarginEnd = iconSize + contentMargin;
-            }
-            result.setRightIconState(largeIconShown, extraMarginEnd, expanderSize);
+            final int extraMarginEndIfVisible = resources.getDimensionPixelSize(
+                    R.dimen.notification_right_icon_size) + contentMargin;
+            result.setRightIconState(largeIconShown, extraMarginEndIfVisible, expanderSize);
         }
 
         /**
@@ -5153,9 +5151,14 @@
 
         private void bindNotificationHeader(RemoteViews contentView, StandardTemplateParams p) {
             bindSmallIcon(contentView, p);
-            boolean hasTextToLeft = bindHeaderAppName(contentView, p);
+            // Populate text left-to-right so that separators are only shown between strings
+            boolean hasTextToLeft = bindHeaderAppName(contentView, p, false /* force */);
             hasTextToLeft |= bindHeaderTextSecondary(contentView, p, hasTextToLeft);
             hasTextToLeft |= bindHeaderText(contentView, p, hasTextToLeft);
+            if (!hasTextToLeft) {
+                // If there's still no text, force add the app name so there is some text.
+                hasTextToLeft |= bindHeaderAppName(contentView, p, true /* force */);
+            }
             bindHeaderChronometerAndTime(contentView, p, hasTextToLeft);
             bindProfileBadge(contentView, p);
             bindAlertedIcon(contentView, p);
@@ -5219,7 +5222,7 @@
                     && mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
                 summaryText = mN.extras.getCharSequence(EXTRA_INFO_TEXT);
             }
-            if (summaryText != null) {
+            if (!TextUtils.isEmpty(summaryText)) {
                 // TODO: Remove the span entirely to only have the string with propper formating.
                 contentView.setTextViewText(R.id.header_text, processTextSpans(
                         processLegacyText(summaryText)));
@@ -5291,13 +5294,13 @@
         /**
          * @return true if the app name will be visible
          */
-        private boolean bindHeaderAppName(RemoteViews contentView, StandardTemplateParams p) {
-            if (p.mViewType == StandardTemplateParams.VIEW_TYPE_MINIMIZED) {
-                contentView.setViewVisibility(R.id.app_name_text, View.GONE);
+        private boolean bindHeaderAppName(RemoteViews contentView, StandardTemplateParams p,
+                boolean force) {
+            if (p.mViewType == StandardTemplateParams.VIEW_TYPE_MINIMIZED && !force) {
+                // unless the force flag is set, don't show the app name in the minimized state.
                 return false;
             }
-            if (p.mHeaderless && !p.mHasCustomContent) {
-                contentView.setViewVisibility(R.id.app_name_text, View.GONE);
+            if (p.mHeaderless && p.hasTitle()) {
                 // the headerless template will have the TITLE in this position; return true to
                 // keep the divider visible between that title and the next text element.
                 return true;
@@ -7759,8 +7762,10 @@
             addExtras(mBuilder.mN.extras);
             if (!isConversationLayout) {
                 // also update the end margin if there is an image
+                // NOTE: This template doesn't support moving this icon to the left, so we don't
+                // need to fully apply the MarginSet
                 contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
-                        bindResult.getHeadingExtraMarginEnd());
+                        bindResult.mHeadingExtraMarginSet.getValue());
             }
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
                     mBuilder.isColorized(p)
@@ -8757,9 +8762,8 @@
             if (!headerless) {
                 // also update the end margin to account for the large icon or expander
                 Resources resources = mBuilder.mContext.getResources();
-                int endMargin = resources.getDimensionPixelSize(
-                        R.dimen.notification_content_margin_end) + result.getTitleMarginEnd();
-                remoteViews.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
+                result.mTitleMarginSet.applyToView(remoteViews, R.id.notification_main_column,
+                        resources.getDimensionPixelOffset(R.dimen.notification_content_margin_end));
             }
         }
 
@@ -10997,42 +11001,74 @@
      */
     private static class TemplateBindResult {
         boolean mRightIconVisible;
-        int mRightIconMarginEnd;
-        int mExpanderSize;
 
         /**
-         * @return the margin end that needs to be added to the heading so that it won't overlap
+         * The margin end that needs to be added to the heading so that it won't overlap
          * with the large icon.  This value includes the space required to accommodate the large
          * icon, but should be added to the space needed to accommodate the expander. This does
          * not include the 16dp content margin that all notification views must have.
          */
-        public int getHeadingExtraMarginEnd() {
-            return mRightIconMarginEnd;
-        }
+        public final MarginSet mHeadingExtraMarginSet = new MarginSet();
 
         /**
-         * @return the margin end that needs to be added to the heading so that it won't overlap
+         * The margin end that needs to be added to the heading so that it won't overlap
          * with the large icon.  This value includes the space required to accommodate the large
          * icon as well as the expander.  This does not include the 16dp content margin that all
          * notification views must have.
          */
-        public int getHeadingFullMarginEnd() {
-            return mRightIconMarginEnd + mExpanderSize;
-        }
+        public final MarginSet mHeadingFullMarginSet = new MarginSet();
 
         /**
-         * @return the margin end that needs to be added to the title text of the big state
+         * The margin end that needs to be added to the title text of the big state
          * so that it won't overlap with the large icon, but assuming the text can run under
          * the expander when that icon is not visible.
          */
-        public int getTitleMarginEnd() {
-            return mRightIconVisible ? getHeadingFullMarginEnd() : 0;
+        public final MarginSet mTitleMarginSet = new MarginSet();
+
+        public void setRightIconState(boolean visible, int marginEndIfVisible, int expanderSize) {
+            mRightIconVisible = visible;
+            mHeadingExtraMarginSet.setValues(0, marginEndIfVisible);
+            mHeadingFullMarginSet.setValues(expanderSize, marginEndIfVisible + expanderSize);
+            mTitleMarginSet.setValues(0, marginEndIfVisible + expanderSize);
         }
 
-        public void setRightIconState(boolean visible, int marginEnd, int expanderSize) {
-            mRightIconVisible = visible;
-            mRightIconMarginEnd = marginEnd;
-            mExpanderSize = expanderSize;
+        /**
+         * This contains the end margins for a view when the right icon is visible or not.  These
+         * values are both needed so that NotificationGroupingUtil can 'move' the right_icon to the
+         * left_icon and adjust the margins, and to undo that change as well.
+         */
+        private class MarginSet {
+            private int mValueIfGone;
+            private int mValueIfVisible;
+
+            public void setValues(int valueIfGone, int valueIfVisible) {
+                mValueIfGone = valueIfGone;
+                mValueIfVisible = valueIfVisible;
+            }
+
+            public void applyToView(@NonNull RemoteViews views, @IdRes int viewId) {
+                applyToView(views, viewId, 0);
+            }
+
+            public void applyToView(@NonNull RemoteViews views, @IdRes int viewId,
+                    @Px int extraMargin) {
+                final int marginEnd = getValue() + extraMargin;
+                if (viewId == R.id.notification_header) {
+                    views.setInt(R.id.notification_header, "setTopLineExtraMarginEnd", marginEnd);
+                } else {
+                    views.setViewLayoutMarginEnd(viewId, marginEnd);
+                }
+                if (mRightIconVisible) {
+                    views.setIntTag(viewId, R.id.tag_margin_end_when_icon_visible,
+                            mValueIfVisible + extraMargin);
+                    views.setIntTag(viewId, R.id.tag_margin_end_when_icon_gone,
+                            mValueIfGone + extraMargin);
+                }
+            }
+
+            public int getValue() {
+                return mRightIconVisible ? mValueIfVisible : mValueIfGone;
+            }
         }
     }
 
@@ -11073,6 +11109,12 @@
             return this;
         }
 
+        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;
+        }
+
         final StandardTemplateParams viewType(int viewType) {
             mViewType = viewType;
             return this;
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index b96b54a..3798de9 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -697,6 +697,10 @@
      * service element of manifest file. The value of attribute
      * {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.</p>
      *
+     * @throws IllegalStateException If the app targeting API is
+     * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from
+     * becoming foreground service due to background restriction.
+     *
      * @param id The identifier for this notification as per
      * {@link NotificationManager#notify(int, Notification)
      * NotificationManager.notify(int, Notification)}; must not be 0.
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 7377790..7287acd 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -284,8 +284,7 @@
                 new CachedServiceFetcher<ActivityTaskManager>() {
             @Override
             public ActivityTaskManager createService(ContextImpl ctx) {
-                return new ActivityTaskManager(
-                        ctx.getOuterContext(), ctx.mMainThread.getHandler());
+                return ActivityTaskManager.getInstance();
             }});
 
         registerService(Context.URI_GRANTS_SERVICE, UriGrantsManager.class,
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index d2be8a4..36241a8 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -92,6 +92,54 @@
                 }
             ],
             "file_patterns": ["(/|^)Activity.java"]
+        },
+        {
+            "name": "CtsContentTestCases",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "org.junit.Ignore"
+                },
+                {
+                    "include-filter": "android.content.wm.cts"
+                }
+            ],
+            "file_patterns": ["(/|^)ContextImpl.java"]
+        },
+        {
+            "name": "CtsOsTestCases",
+            "options": [
+                {
+                    "include-annotation": "android.platform.test.annotations.Presubmit"
+                },
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "org.junit.Ignore"
+                },
+                {
+                    "include-filter": "android.os.cts.StrictModeTest"
+                }
+            ],
+            "file_patterns": ["(/|^)ContextImpl.java"]
+        },
+        {
+            "name": "FrameworksCoreTests",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "org.junit.Ignore"
+                },
+                {
+                    "include-filter": "android.content.ContextTest"
+                }
+            ],
+            "file_patterns": ["(/|^)ContextImpl.java"]
         }
     ],
     "postsubmit": [
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index ca67dba..1a8a4b7 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -214,7 +214,6 @@
      */
     public int parentTaskId;
 
-
     /**
      * Parent bounds.
      * @hide
@@ -227,6 +226,12 @@
      */
     public boolean isFocused;
 
+    /**
+     * Whether this task is visible.
+     * @hide
+     */
+    public boolean isVisible;
+
     TaskInfo() {
         // Do nothing
     }
@@ -311,7 +316,8 @@
                 && pictureInPictureParams == that.pictureInPictureParams
                 && getWindowingMode() == that.getWindowingMode()
                 && Objects.equals(taskDescription, that.taskDescription)
-                && isFocused == that.isFocused;
+                && isFocused == that.isFocused
+                && isVisible == that.isVisible;
     }
 
     private boolean equalsLetterboxParams(TaskInfo that) {
@@ -358,6 +364,7 @@
         parentTaskId = source.readInt();
         parentBounds = source.readTypedObject(Rect.CREATOR);
         isFocused = source.readBoolean();
+        isVisible = source.readBoolean();
     }
 
     /**
@@ -394,6 +401,7 @@
         dest.writeInt(parentTaskId);
         dest.writeTypedObject(parentBounds, flags);
         dest.writeBoolean(isFocused);
+        dest.writeBoolean(isVisible);
     }
 
     @Override
@@ -413,12 +421,13 @@
                 + " topActivityType=" + topActivityType
                 + " pictureInPictureParams=" + pictureInPictureParams
                 + " topActivityInfo=" + topActivityInfo
-                + " launchCookies" + launchCookies
+                + " launchCookies=" + launchCookies
                 + " letterboxActivityBounds=" + letterboxActivityBounds
                 + " positionInParent=" + positionInParent
                 + " parentTaskId=" + parentTaskId
                 + " parentBounds=" + parentBounds
                 + " isFocused=" + isFocused
+                + " isVisible=" + isVisible
                 + "}";
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 16ae081..5eb1922 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -87,6 +87,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -2453,19 +2454,45 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface PersonalAppsSuspensionReason {}
 
+    // TODO(b/172376923) - make all (or none) @TestApi
+
     /** @hide */
     @TestApi
     public static final int OPERATION_LOCK_NOW = 1;
 
+    /** @hide */
+    public static final int OPERATION_SWITCH_USER = 2;
+    /** @hide */
+    public static final int OPERATION_START_USER_IN_BACKGROUND = 3;
+    /** @hide */
+    public static final int OPERATION_STOP_USER = 4;
+    /** @hide */
+    public static final int OPERATION_CREATE_AND_MANAGE_USER = 5;
+    /** @hide */
+    public static final int OPERATION_REMOVE_USER = 6;
+
+    private static final String PREFIX_OPERATION = "OPERATION_";
+
+
     // TODO(b/172376923) - add all operations
     /** @hide */
-    @IntDef(prefix = "OPERATION_", value = {
+    @IntDef(prefix = PREFIX_OPERATION, value = {
             OPERATION_LOCK_NOW,
+            OPERATION_SWITCH_USER,
+            OPERATION_START_USER_IN_BACKGROUND,
+            OPERATION_STOP_USER,
+            OPERATION_CREATE_AND_MANAGE_USER,
+            OPERATION_REMOVE_USER
     })
     @Retention(RetentionPolicy.SOURCE)
     public static @interface DevicePolicyOperation {
     }
 
+    /** @hide */
+    public static String operationToString(@DevicePolicyOperation int operation) {
+        return DebugUtils.constantToString(DevicePolicyManager.class, PREFIX_OPERATION, operation);
+    }
+
     /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
@@ -3721,6 +3748,27 @@
     }
 
     /**
+     * Returns the password complexity that applies to this user, aggregated from other users if
+     * necessary (for example, if the DPC has set password complexity requirements on the parent
+     * profile DPM instance of a managed profile user, they would apply to the primary user on the
+     * device).
+     * @hide
+     */
+    @PasswordComplexity
+    public int getAggregatedPasswordComplexityForUser(int userId) {
+        if (mService == null) {
+            return PASSWORD_COMPLEXITY_NONE;
+        }
+
+        try {
+            return mService.getAggregatedPasswordComplexityForUser(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+
+    /**
      * When called by a profile owner of a managed profile returns true if the profile uses unified
      * challenge with its parent user.
      *
@@ -5192,9 +5240,22 @@
     }
 
     /**
-     * Called by a device or profile owner, or delegated certificate installer, to install a
-     * certificate and corresponding private key. All apps within the profile will be able to access
-     * the certificate and use the private key, given direct user approval.
+     * This API can be called by the following to install a certificate and corresponding
+     * private key:
+     * <ul>
+     *    <li>Device owner</li>
+     *    <li>Profile owner</li>
+     *    <li>Delegated certificate installer</li>
+     *    <li>Credential management app</li>
+     * </ul>
+     * All apps within the profile will be able to access the certificate and use the private key,
+     * given direct user approval.
+     *
+     * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+     * can call this API. However, this API sets the key pair as user selectable by default,
+     * which is not permitted when called by the credential management app. Instead,
+     * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} should be
+     * called with {@link #INSTALLKEY_SET_USER_SELECTABLE} not set as a flag.
      *
      * <p>Access to the installed credentials will not be granted to the caller of this API without
      * direct user approval. This is for security - should a certificate installer become
@@ -5225,10 +5286,23 @@
     }
 
     /**
-     * Called by a device or profile owner, or delegated certificate installer, to install a
-     * certificate chain and corresponding private key for the leaf certificate. All apps within the
-     * profile will be able to access the certificate chain and use the private key, given direct
-     * user approval.
+     * This API can be called by the following to install a certificate chain and corresponding
+     * private key for the leaf certificate:
+     * <ul>
+     *    <li>Device owner</li>
+     *    <li>Profile owner</li>
+     *    <li>Delegated certificate installer</li>
+     *    <li>Credential management app</li>
+     * </ul>
+     * All apps within the profile will be able to access the certificate chain and use the private
+     * key, given direct user approval.
+     *
+     * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+     * can call this API. However, this API sets the key pair as user selectable by default,
+     * which is not permitted when called by the credential management app. Instead,
+     * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} should be
+     * called with {@link #INSTALLKEY_SET_USER_SELECTABLE} not set as a flag.
+     * Note, there can only be a credential management app on an unmanaged device.
      *
      * <p>The caller of this API may grant itself access to the certificate and private key
      * immediately, without user approval. It is a best practice not to request this unless strictly
@@ -5266,10 +5340,26 @@
     }
 
     /**
-     * Called by a device or profile owner, or delegated certificate installer, to install a
-     * certificate chain and corresponding private key for the leaf certificate. All apps within the
-     * profile will be able to access the certificate chain and use the private key, given direct
-     * user approval (if the user is allowed to select the private key).
+     * This API can be called by the following to install a certificate chain and corresponding
+     * private key for the leaf certificate:
+     * <ul>
+     *    <li>Device owner</li>
+     *    <li>Profile owner</li>
+     *    <li>Delegated certificate installer</li>
+     *    <li>Credential management app</li>
+     * </ul>
+     * All apps within the profile will be able to access the certificate chain and use the
+     * private key, given direct user approval (if the user is allowed to select the private key).
+     *
+     * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+     * can call this API. If called by the credential management app:
+     * <ul>
+     *    <li>The componentName must be {@code null}r</li>
+     *    <li>The alias must exist in the credential management app's
+     *    {@link android.security.AppUriAuthenticationPolicy}</li>
+     *    <li>The key pair must not be user selectable</li>
+     * </ul>
+     * Note, there can only be a credential management app on an unmanaged device.
      *
      * <p>The caller of this API may grant itself access to the certificate and private key
      * immediately, without user approval. It is a best practice not to request this unless strictly
@@ -5295,7 +5385,8 @@
      *        {@link #INSTALLKEY_REQUEST_CREDENTIALS_ACCESS}.
      * @return {@code true} if the keys were installed, {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
-     *         owner.
+     *         owner, or {@code admin} is null but the calling application is not a delegated
+     *         certificate installer or credential management app.
      * @see android.security.KeyChain#getCertificateChain
      * @see #setDelegatedScopes
      * @see #DELEGATION_CERT_INSTALL
@@ -5328,15 +5419,26 @@
     }
 
     /**
-     * Called by a device or profile owner, or delegated certificate installer, to remove a
-     * certificate and private key pair installed under a given alias.
+     * This API can be called by the following to remove a certificate and private key pair
+     * installed under a given alias:
+     * <ul>
+     *    <li>Device owner</li>
+     *    <li>Profile owner</li>
+     *    <li>Delegated certificate installer</li>
+     *    <li>Credential management app</li>
+     * </ul>
+     *
+     * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+     * can call this API. If called by the credential management app, the componentName must be
+     * {@code null}. Note, there can only be a credential management app on an unmanaged device.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *        {@code null} if calling from a delegated certificate installer.
      * @param alias The private key alias under which the certificate is installed.
      * @return {@code true} if the private key alias no longer exists, {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
-     *         owner.
+     *         owner, or {@code admin} is null but the calling application is not a delegated
+     *         certificate installer or credential management app.
      * @see #setDelegatedScopes
      * @see #DELEGATION_CERT_INSTALL
      */
@@ -5349,11 +5451,42 @@
         }
     }
 
+    // STOPSHIP(b/174298501): clarify the expected return value following generateKeyPair call.
     /**
-     * Called by a device or profile owner, or delegated certificate installer, to generate a
-     * new private/public key pair. If the device supports key generation via secure hardware,
-     * this method is useful for creating a key in KeyChain that never left the secure hardware.
-     * Access to the key is controlled the same way as in {@link #installKeyPair}.
+     * Called by a device or profile owner, or delegated certificate installer, to query whether a
+     * certificate and private key are installed under a given alias.
+     *
+     * @param alias The alias under which the key pair is installed.
+     * @return {@code true} if a key pair with this alias exists, {@code false} otherwise.
+     * @throws SecurityException if the caller is not a device or profile owner or a delegated
+     *         certificate installer.
+     * @see #setDelegatedScopes
+     * @see #DELEGATION_CERT_INSTALL
+     */
+    public boolean hasKeyPair(@NonNull String alias) {
+        throwIfParentInstance("hasKeyPair");
+        try {
+            return mService.hasKeyPair(mContext.getPackageName(), alias);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * This API can be called by the following to generate a new private/public key pair:
+     * <ul>
+     *    <li>Device owner</li>
+     *    <li>Profile owner</li>
+     *    <li>Delegated certificate installer</li>
+     *    <li>Credential management app</li>
+     * </ul>
+     * If the device supports key generation via secure hardware, this method is useful for
+     * creating a key in KeyChain that never left the secure hardware. Access to the key is
+     * controlled the same way as in {@link #installKeyPair}.
+     *
+     * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+     * can call this API. If called by the credential management app, the componentName must be
+     * {@code null}. Note, there can only be a credential management app on an unmanaged device.
      *
      * <p>Because this method might take several seconds to complete, it should only be called from
      * a worker thread. This method returns {@code null} when called from the main thread.
@@ -5376,9 +5509,10 @@
      * supports these features, refer to {@link #isDeviceIdAttestationSupported()} and
      * {@link #isUniqueDeviceAttestationSupported()}.
      *
-     * <p>Device owner, profile owner and their delegated certificate installer can use
-     * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information
-     * including manufacturer, model, brand, device and product in the attestation record.
+     * <p>Device owner, profile owner, their delegated certificate installer and the credential
+     * management app can use {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device
+     * information including manufacturer, model, brand, device and product in the attestation
+     * record.
      * Only device owner, profile owner on an organization-owned device and their delegated
      * certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and
      * {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial number,
@@ -5413,9 +5547,11 @@
      *        {@code keySpec}.
      * @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise.
      * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
-     *         owner. If Device ID attestation is requested (using {@link #ID_TYPE_SERIAL},
-     *         {@link #ID_TYPE_IMEI} or {@link #ID_TYPE_MEID}), the caller must be the Device Owner
-     *         or the Certificate Installer delegate.
+     *         owner, or {@code admin} is null but the calling application is not a delegated
+     *         certificate installer or credential management app. If Device ID attestation is
+     *         requested (using {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} or
+     *         {@link #ID_TYPE_MEID}), the caller must be the Device Owner or the Certificate
+     *         Installer delegate.
      * @throws IllegalArgumentException in the following cases:
      *         <p>
      *         <ul>
@@ -5578,10 +5714,19 @@
     }
 
     /**
-     * Called by a device or profile owner, or delegated certificate installer, to associate
-     * certificates with a key pair that was generated using {@link #generateKeyPair}, and
-     * set whether the key is available for the user to choose in the certificate selection
-     * prompt.
+     * This API can be called by the following to associate certificates with a key pair that was
+     * generated using {@link #generateKeyPair}, and set whether the key is available for the user
+     * to choose in the certificate selection prompt:
+     * <ul>
+     *    <li>Device owner</li>
+     *    <li>Profile owner</li>
+     *    <li>Delegated certificate installer</li>
+     *    <li>Credential management app</li>
+     * </ul>
+     *
+     * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+     * can call this API. If called by the credential management app, the componentName must be
+     * {@code null}. Note, there can only be a credential management app on an unmanaged device.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *            {@code null} if calling from a delegated certificate installer.
@@ -5599,7 +5744,7 @@
      *        successfully associated with it, {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
      *         owner, or {@code admin} is null but the calling application is not a delegated
-     *         certificate installer.
+     *         certificate installer or credential management app.
      */
     public boolean setKeyPairCertificate(@Nullable ComponentName admin,
             @NonNull String alias, @NonNull List<Certificate> certs, boolean isUserSelectable) {
@@ -6436,6 +6581,8 @@
     }
 
     /**
+     * Called by a privileged caller holding {@code BIND_DEVICE_ADMIN} permission to retrieve
+     * the remove warning for the given device admin.
      * @hide
      */
     public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) {
@@ -8505,6 +8652,8 @@
      * it previously set with {@link #addUserRestriction(ComponentName, String)}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return a {@link Bundle} whose keys are the user restrictions, and the values a
+     * {@code boolean} indicating whether the restriction is set.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public @NonNull Bundle getUserRestrictions(@NonNull ComponentName admin) {
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index cb879fc..c02fcab 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -16,6 +16,7 @@
 
 package android.app.admin;
 
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -229,5 +230,11 @@
     /**
      * Returns the profile owner component for the given user, or {@code null} if there is not one.
      */
+    @Nullable
     public abstract ComponentName getProfileOwnerAsUser(int userHandle);
+
+    /**
+     * Returns whether the given package is a device owner or a profile owner in the calling user.
+     */
+    public abstract boolean isDeviceOrProfileOwnerInCallingUser(String packageName);
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 58368bc..8be3cdc 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -89,6 +89,7 @@
     int getPasswordComplexity(boolean parent);
     void setRequiredPasswordComplexity(int passwordComplexity, boolean parent);
     int getRequiredPasswordComplexity(boolean parent);
+    int getAggregatedPasswordComplexityForUser(int userId);
     boolean isUsingUnifiedPassword(in ComponentName admin);
     int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
     int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
@@ -184,6 +185,7 @@
             in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess,
             boolean isUserSelectable);
     boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
+    boolean hasKeyPair(in String callerPackage, in String alias);
     boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm,
             in ParcelableKeyGenParameterSpec keySpec,
             in int idAttestationFlags, out KeymasterCertificateChain attestationChain);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 86f91d7..1cf4567 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -85,7 +85,8 @@
             TAG_CRYPTO_SELF_TEST_COMPLETED,
             TAG_KEY_INTEGRITY_VIOLATION,
             TAG_CERT_VALIDATION_FAILURE,
-            TAG_CAMERA_POLICY_SET
+            TAG_CAMERA_POLICY_SET,
+            TAG_PASSWORD_COMPLEXITY_REQUIRED
     })
     public @interface SecurityLogTag {}
 
@@ -478,6 +479,21 @@
             SecurityLogTags.SECURITY_CAMERA_POLICY_SET;
 
     /**
+     * Indicates that an admin has set a password complexity requirement, using the platform's
+     * pre-defined complexity levels. The log entry contains the following information about the
+     * event, encapsulated in an {@link Object} array and accessible via
+     * {@link SecurityEvent#getData()}:
+     * <li> [0] admin package name ({@code String})
+     * <li> [1] admin user ID ({@code Integer})
+     * <li> [2] target user ID ({@code Integer})
+     * <li> [3] Password complexity ({@code Integer})
+     *
+     * @see DevicePolicyManager#setRequiredPasswordComplexity(int)
+     */
+    public static final int TAG_PASSWORD_COMPLEXITY_REQUIRED =
+            SecurityLogTags.SECURITY_PASSWORD_COMPLEXITY_REQUIRED;
+
+    /**
      * Event severity level indicating that the event corresponds to normal workflow.
      */
     public static final int LEVEL_INFO = 1;
@@ -617,6 +633,7 @@
                 case TAG_USER_RESTRICTION_ADDED:
                 case TAG_USER_RESTRICTION_REMOVED:
                 case TAG_CAMERA_POLICY_SET:
+                case TAG_PASSWORD_COMPLEXITY_REQUIRED:
                     return LEVEL_INFO;
                 case TAG_CERT_AUTHORITY_REMOVED:
                 case TAG_CRYPTO_SELF_TEST_COMPLETED:
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index 100fd4c..db5245c 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -1,4 +1,4 @@
-# See system/core/logcat/event.logtags for a description of the format of this file.
+# See system/logging/logcat/event.logtags for a description of the format of this file.
 
 option java_package android.app.admin
 
@@ -39,3 +39,4 @@
 210032 security_key_integrity_violation         (key_id|3),(uid|1)
 210033 security_cert_validation_failure         (reason|3)
 210034 security_camera_policy_set               (package|3),(admin_user|1),(target_user|1),(disabled|1)
+210035 security_password_complexity_required    (package|3),(admin_user|1),(target_user|1),(complexity|1)
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index f5674e5..e870597 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -18,7 +18,12 @@
 
 import android.annotation.NonNull;
 import android.content.Intent;
+import android.content.pm.LauncherApps;
 import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Parcel;
@@ -147,10 +152,10 @@
             mPackageName = intent == null ? null : intent.getPackage();
         }
 
-        public Builder(ShortcutInfo info) {
+        public Builder(ShortcutInfo info, LauncherApps launcherApps) {
             mId = info.getId();
             mUserName = info.getLabel();
-            mUserIcon = info.getIcon();
+            mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
             mUid = info.getUserId();
             mPackageName = info.getPackage();
         }
@@ -270,4 +275,32 @@
                     return new PeopleSpaceTile[size];
                 }
             };
+
+    /** Converts {@code drawable} to a {@link Icon}. */
+    public static Icon convertDrawableToIcon(Drawable drawable) {
+        if (drawable == null) {
+            return null;
+        }
+
+        if (drawable instanceof BitmapDrawable) {
+            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+            if (bitmapDrawable.getBitmap() != null) {
+                return Icon.createWithBitmap(bitmapDrawable.getBitmap());
+            }
+        }
+
+        Bitmap bitmap;
+        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+            // Single color bitmap will be created of 1x1 pixel
+        } else {
+            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+                    drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+        }
+
+        Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        drawable.draw(canvas);
+        return Icon.createWithBitmap(bitmap);
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 3a65aaa..7764ebe 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -18,7 +18,6 @@
 
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -40,7 +39,7 @@
      * This extra represents the current codec status of the A2DP
      * profile.
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage
     public static final String EXTRA_CODEC_STATUS =
             "android.bluetooth.extra.CODEC_STATUS";
 
@@ -199,7 +198,7 @@
      *
      * @return the current codec configuration
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage
     public @Nullable BluetoothCodecConfig getCodecConfig() {
         return mCodecConfig;
     }
@@ -209,7 +208,7 @@
      *
      * @return an array with the codecs local capabilities
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage
     public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() {
         return mCodecsLocalCapabilities;
     }
@@ -219,7 +218,7 @@
      *
      * @return an array with the codecs selectable capabilities
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage
     public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
         return mCodecsSelectableCapabilities;
     }
diff --git a/core/java/android/companion/OWNERS b/core/java/android/companion/OWNERS
new file mode 100644
index 0000000..da723b3
--- /dev/null
+++ b/core/java/android/companion/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com
\ No newline at end of file
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e35fb03..d7dc86a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -63,7 +63,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.storage.StorageManager;
 import android.system.Int32Ref;
 import android.text.TextUtils;
 import android.util.EventLog;
@@ -110,7 +109,7 @@
      *
      * @hide
      */
-    public static final boolean DEPRECATE_DATA_COLUMNS = StorageManager.hasIsolatedStorage();
+    public static final boolean DEPRECATE_DATA_COLUMNS = true;
 
     /**
      * Special filesystem path prefix which indicates that a path should be
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6a3f6b4..8f92bf1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -367,6 +367,16 @@
     /***********    Hidden flags below this line ***********/
 
     /**
+     * Flag for {@link #bindService}: allow background foreground service starts from the bound
+     * service's process.
+     * This flag is only respected if the caller is holding
+     * {@link android.Manifest.permission#START_FOREGROUND_SERVICES_FROM_BACKGROUND}.
+     * @hide
+     */
+    @SystemApi
+    public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 0x00040000;
+
+    /**
      * Flag for {@link #bindService}: This flag is intended to be used only by the system to adjust
      * the scheduling policy for IMEs (and any other out-of-process user-visible components that
      * work closely with the top app) so that UI hosted in such services can have the same
@@ -3107,6 +3117,10 @@
      * @throws SecurityException If the caller does not have permission to access the service
      * or the service can not be found.
      *
+     * @throws IllegalStateException If the caller app's targeting API is
+     * {@link android.os.Build.VERSION_CODES#S} or later, and the foreground service is restricted
+     * from start due to background restriction.
+     *
      * @see #stopService
      * @see android.app.Service#startForeground(int, android.app.Notification)
      */
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
new file mode 100644
index 0000000..a2880df
--- /dev/null
+++ b/core/java/android/content/TEST_MAPPING
@@ -0,0 +1,52 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsContentTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.content.wm.cts"
+        }
+      ],
+      "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+    },
+    {
+      "name": "CtsOsTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.os.cts.StrictModeTest"
+        }
+      ],
+      "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+    },
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.content.ContextTest"
+        }
+      ],
+      "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 8b411d5..b290679 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -119,8 +119,9 @@
      *        {@link #getTargetUserProfiles()} if different to the calling user, otherwise a
      *        {@link SecurityException} will be thrown.
      * @param callingActivity The activity to start the new activity from for the purposes of
-     *        deciding which task the new activity should belong to. If {@code null}, the activity
-     *        will always be started in a new task.
+     *        passing back any result and deciding which task the new activity should belong to. If
+     *        {@code null}, the activity will always be started in a new task and no result will be
+     *        returned.
      */
     @RequiresPermission(anyOf = {
             android.Manifest.permission.INTERACT_ACROSS_PROFILES,
@@ -146,8 +147,9 @@
      *        {@link #getTargetUserProfiles()} if different to the calling user, otherwise a
      *        {@link SecurityException} will be thrown.
      * @param callingActivity The activity to start the new activity from for the purposes of
-     *        deciding which task the new activity should belong to. If {@code null}, the activity
-     *        will always be started in a new task.
+     *        passing back any result and deciding which task the new activity should belong to. If
+     *        {@code null}, the activity will always be started in a new task and no result will be
+     *        returned.
      * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
      */
     @RequiresPermission(anyOf = {
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index c6450ff..cd9ba6a 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -251,6 +251,16 @@
     @SystemApi
     public static final int PROTECTION_FLAG_RETAIL_DEMO = 0x1000000;
 
+    /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>recents</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int PROTECTION_FLAG_RECENTS = 0x2000000;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
             PROTECTION_FLAG_PRIVILEGED,
@@ -274,6 +284,7 @@
             PROTECTION_FLAG_APP_PREDICTOR,
             PROTECTION_FLAG_COMPANION,
             PROTECTION_FLAG_RETAIL_DEMO,
+            PROTECTION_FLAG_RECENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProtectionFlags {}
@@ -532,6 +543,9 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0) {
             protLevel.append("|retailDemo");
         }
+        if ((level & PermissionInfo.PROTECTION_FLAG_RECENTS) != 0) {
+            protLevel.append("|recents");
+        }
         return protLevel.toString();
     }
 
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 8625637..a60e642 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -114,15 +114,6 @@
         mIsNative = isNative;
     }
 
-    /** @hide */
-    public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
-            String name, long version, int type,
-            VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
-            List<SharedLibraryInfo> dependencies) {
-        this(path, packageName, codePaths, name, version, type, declaringPackage, dependentPackages,
-            dependencies, false /* isNative */);
-    }
-
     private SharedLibraryInfo(Parcel parcel) {
         mPath = parcel.readString8();
         mPackageName = parcel.readString8();
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
index 2189de08..0b81c6c 100644
--- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -16,13 +16,10 @@
 
 package android.hardware.biometrics;
 
-import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * The base class containing all modality-agnostic information. This is a superset of the
  * {@link android.hardware.biometrics.common.CommonProps}, and provides backwards-compatible
@@ -35,6 +32,11 @@
     @SensorProperties.Strength public final int sensorStrength;
     public final int maxEnrollmentsPerUser;
 
+    public static SensorPropertiesInternal from(@NonNull SensorPropertiesInternal prop) {
+        return new SensorPropertiesInternal(prop.sensorId, prop.sensorStrength,
+                prop.maxEnrollmentsPerUser);
+    }
+
     protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
             int maxEnrollmentsPerUser) {
         this.sensorId = sensorId;
@@ -72,4 +74,10 @@
         dest.writeInt(sensorStrength);
         dest.writeInt(maxEnrollmentsPerUser);
     }
+
+    @Override
+    public String toString() {
+        return "ID: " + sensorId + ", Strength: " + sensorStrength
+                + ", MaxEnrollmentsPerUser: " + maxEnrollmentsPerUser;
+    }
 }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 3290022..ca5eeb1 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -911,12 +911,52 @@
     public interface DeviceConfig {
 
         /**
-         * Key for refresh rate in the zone defined by thresholds.
+         * Key for refresh rate in the low zone defined by thresholds.
          *
+         * Note that the name and value don't match because they were added before we had a high
+         * zone to consider.
          * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
          * @see android.R.integer#config_defaultZoneBehavior
          */
-        String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone";
+        String KEY_REFRESH_RATE_IN_LOW_ZONE = "refresh_rate_in_zone";
+
+        /**
+         * Key for accessing the low display brightness thresholds for the configured refresh
+         * rate zone.
+         * The value will be a pair of comma separated integers representing the minimum and maximum
+         * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
+         *
+         * Note that the name and value don't match because they were added before we had a high
+         * zone to consider.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
+         * @hide
+         */
+        String KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS =
+                "peak_refresh_rate_brightness_thresholds";
+
+        /**
+         * Key for accessing the low ambient brightness thresholds for the configured refresh
+         * rate zone. The value will be a pair of comma separated integers representing the minimum
+         * and maximum thresholds of the zone, respectively, in lux.
+         *
+         * Note that the name and value don't match because they were added before we had a high
+         * zone to consider.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
+         * @hide
+         */
+        String KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS =
+                "peak_refresh_rate_ambient_thresholds";
+        /**
+         * Key for refresh rate in the high zone defined by thresholds.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+         * @see android.R.integer#config_fixedRefreshRateInHighZone
+         */
+        String KEY_REFRESH_RATE_IN_HIGH_ZONE = "refresh_rate_in_high_zone";
 
         /**
          * Key for accessing the display brightness thresholds for the configured refresh rate zone.
@@ -924,11 +964,11 @@
          * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
          *
          * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
-         * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
+         * @see android.R.array#config_brightnessHighThresholdsOfFixedRefreshRate
          * @hide
          */
-        String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS =
-                "peak_refresh_rate_brightness_thresholds";
+        String KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS =
+                "fixed_refresh_rate_high_display_brightness_thresholds";
 
         /**
          * Key for accessing the ambient brightness thresholds for the configured refresh rate zone.
@@ -936,12 +976,11 @@
          * thresholds of the zone, respectively, in lux.
          *
          * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
-         * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
+         * @see android.R.array#config_ambientHighThresholdsOfFixedRefreshRate
          * @hide
          */
-        String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS =
-                "peak_refresh_rate_ambient_thresholds";
-
+        String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
+                "fixed_refresh_rate_high_ambient_brightness_thresholds";
         /**
          * Key for default peak refresh rate
          *
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index b046d1d..7b4889f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -358,7 +358,7 @@
                     // listener.
                     DisplayInfo display = getDisplayInfoLocked(displayId);
                     if (display != null) {
-                        float refreshRate = display.getMode().getRefreshRate();
+                        float refreshRate = display.getRefreshRate();
                         // Signal native callbacks if we ever set a refresh rate.
                         nSignalNativeCallbacks(refreshRate);
                     }
@@ -862,7 +862,7 @@
             if (display != null) {
                 // We need to tell AChoreographer instances the current refresh rate so that apps
                 // can get it for free once a callback first registers.
-                float refreshRate = display.getMode().getRefreshRate();
+                float refreshRate = display.getRefreshRate();
                 nSignalNativeCallbacks(refreshRate);
             }
         }
diff --git a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
index e91554b..b9c0d12 100644
--- a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
+++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
@@ -19,7 +19,6 @@
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * Container for face sensor properties.
@@ -78,4 +77,9 @@
         dest.writeBoolean(supportsFaceDetection);
         dest.writeBoolean(supportsSelfIllumination);
     }
+
+    @Override
+    public String toString() {
+        return "ID: " + sensorId + ", Strength: " + sensorStrength;
+    }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
index 3fd20f1..c6007f1 100644
--- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
@@ -513,4 +513,19 @@
                 && mDeviceId == other.mDeviceId
                 && mAdopterId == other.mAdopterId;
     }
+
+    @Override
+    public int hashCode() {
+        return java.util.Objects.hash(
+                mHdmiDeviceType,
+                mPhysicalAddress,
+                mPortId,
+                mLogicalAddress,
+                mDeviceType,
+                mVendorId,
+                mDevicePowerStatus,
+                mDisplayName,
+                mDeviceId,
+                mAdopterId);
+    }
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 7fb73ce..81ea2f5 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -56,6 +56,7 @@
 import android.view.VerifiedInputEvent;
 import android.view.WindowManager.LayoutParams;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 
@@ -275,6 +276,21 @@
      *
      * @hide
      */
+    @VisibleForTesting
+    public static InputManager resetInstance(IInputManager inputManagerService) {
+        synchronized (InputManager.class) {
+            sInstance = new InputManager(inputManagerService);
+            return sInstance;
+        }
+    }
+
+    /**
+     * Gets an instance of the input manager.
+     *
+     * @return The input manager instance.
+     *
+     * @hide
+     */
     @UnsupportedAppUsage
     public static InputManager getInstance() {
         synchronized (InputManager.class) {
@@ -1428,7 +1444,7 @@
 
         @Override
         public boolean hasAmplitudeControl() {
-            return false;
+            return true;
         }
 
         /**
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index e9de274..0766917 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -54,6 +54,8 @@
     private static final int DO_VIEW_CLICKED = 115;
     private static final int DO_NOTIFY_IME_HIDDEN = 120;
     private static final int DO_REMOVE_IME_SURFACE = 130;
+    private static final int DO_FINISH_INPUT = 140;
+
 
     @UnsupportedAppUsage
     HandlerCaller mCaller;
@@ -141,6 +143,10 @@
                 mInputMethodSession.removeImeSurface();
                 return;
             }
+            case DO_FINISH_INPUT: {
+                mInputMethodSession.finishInput();
+                return;
+            }
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
@@ -222,6 +228,10 @@
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
     }
 
+    @Override
+    public void finishInput() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT));
+    }
     private final class ImeInputEventReceiver extends InputEventReceiver
             implements InputMethodSession.EventCallback {
         private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ae260e1..67e75d2 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -61,9 +61,12 @@
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.UiContext;
 import android.app.ActivityManager;
 import android.app.Dialog;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -411,7 +414,29 @@
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     int mTheme = 0;
-    
+
+    /**
+     * Finish the {@link InputConnection} when the device becomes
+     * {@link android.os.PowerManager#isInteractive non-interactive}.
+     *
+     * <p>
+     * If enabled by the current {@link InputMethodService input method}, the current input
+     * connection will be {@link InputMethodService#onFinishInput finished} whenever the devices
+     * becomes non-interactive.
+     *
+     * <p>
+     * If not enabled, the current input connection will instead be silently deactivated when the
+     * devices becomes non-interactive, and an {@link InputMethodService#onFinishInput
+     * onFinishInput()} {@link InputMethodService#onStartInput onStartInput()} pair is dispatched
+     * when the device becomes interactive again.
+     *
+     * @hide
+     */
+    @TestApi
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+    public static final long FINISH_INPUT_NO_FALLBACK_CONNECTION = 156215187L; // This is a bug id.
+
     LayoutInflater mInflater;
     TypedArray mThemeAttrs;
     @UnsupportedAppUsage
@@ -560,10 +585,12 @@
                 Log.w(TAG, "The token has already registered, ignore this initialization.");
                 return;
             }
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
             mPrivOps.set(privilegedOperations);
             InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
             updateInputMethodDisplay(displayId);
             attachToken(token);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
         /**
@@ -617,6 +644,7 @@
         @MainThread
         @Override
         public void bindInput(InputBinding binding) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.bindInput");
             mInputBinding = binding;
             mInputConnection = binding.getConnection();
             if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
@@ -624,6 +652,7 @@
             reportFullscreenMode();
             initialize();
             onBindInput();
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
         /**
@@ -661,7 +690,9 @@
         @Override
         public void restartInput(InputConnection ic, EditorInfo attribute) {
             if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.restartInput");
             doStartInput(ic, attribute, true);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
         /**
@@ -1228,6 +1259,7 @@
     }
 
     @Override public void onCreate() {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.onCreate");
         mTheme = Resources.selectSystemTheme(mTheme,
                 getApplicationInfo().targetSdkVersion,
                 android.R.style.Theme_InputMethod,
@@ -1248,6 +1280,7 @@
         // in non-default display.
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initSoftInputWindow");
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
         mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
@@ -1269,10 +1302,12 @@
 
         initViews();
         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
         mInlineSuggestionSessionController = new InlineSuggestionSessionController(
                 this::onCreateInlineSuggestionsRequest, this::getHostInputToken,
                 this::onInlineSuggestionsResponse);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
     /**
@@ -1293,6 +1328,7 @@
     }
 
     void initViews() {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initViews");
         mInitialized = false;
         mViewsCreated = false;
         mShowInputRequested = false;
@@ -1327,6 +1363,7 @@
         mCandidatesVisibility = getCandidatesHiddenVisibility();
         mCandidatesFrame.setVisibility(mCandidatesVisibility);
         mInputFrame.setVisibility(View.GONE);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
     @Override public void onDestroy() {
@@ -1368,6 +1405,7 @@
     }
 
     private void resetStateForNewConfiguration() {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.resetStateForNewConfiguration");
         boolean visible = mDecorViewVisible;
         int showFlags = mShowInputFlags;
         boolean showingInput = mShowInputRequested;
@@ -1403,6 +1441,7 @@
             boolean showing = onEvaluateInputViewShown();
             setImeWindowStatus(IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
         }
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
     /**
@@ -1564,6 +1603,7 @@
      * is currently running in fullscreen mode.
      */
     public void updateFullscreenMode() {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.updateFullscreenMode");
         boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
         boolean changed = mLastShowInputRequested != mShowInputRequested;
         if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
@@ -1602,6 +1642,7 @@
             onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
             mLastShowInputRequested = mShowInputRequested;
         }
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
     
     /**
@@ -1730,6 +1771,7 @@
      * @param outInsets Fill in with the current UI insets.
      */
     public void onComputeInsets(Insets outInsets) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.onComputeInsets");
         int[] loc = mTmpLocation;
         if (mInputFrame.getVisibility() == View.VISIBLE) {
             mInputFrame.getLocationInWindow(loc);
@@ -1750,6 +1792,7 @@
         outInsets.visibleTopInsets = loc[1];
         outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
         outInsets.touchableRegion.setEmpty();
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
     
     /**
@@ -2140,7 +2183,7 @@
         }
 
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this);
-
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
         mDecorViewWasVisible = mDecorViewVisible;
         mInShowWindow = true;
         final int previousImeWindowStatus =
@@ -2164,6 +2207,7 @@
         }
         mDecorViewWasVisible = true;
         mInShowWindow = false;
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
 
@@ -2325,7 +2369,7 @@
     }
 
     void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
-        if (!restarting) {
+        if (!restarting && mInputStarted) {
             doFinishInput();
         }
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this);
diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
index dbb669b..2db9ed1 100644
--- a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
+++ b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
@@ -23,6 +23,7 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.util.Log;
 import android.view.InputChannel;
@@ -38,8 +39,8 @@
 import android.view.inputmethod.ExtractedText;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.inputmethod.IMultiClientInputMethodSession;
 import com.android.internal.inputmethod.CancellationGroup;
+import com.android.internal.inputmethod.IMultiClientInputMethodSession;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.view.IInputContext;
@@ -303,6 +304,12 @@
             // no-op for multi-session
             reportNotSupported();
         }
+
+        @Override
+        public void finishInput() throws RemoteException {
+            // no-op for multi-session
+            reportNotSupported();
+        }
     }
 
     private static final class MultiClientInputMethodSessionImpl
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 44ebff9..0676ad4 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -40,6 +40,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.time.Duration;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -174,6 +175,14 @@
     public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
 
     /**
+     * Sent by the NetworkAgent to ConnectivityService to pass the current
+     * list of underlying networks.
+     * obj = array of Network objects
+     * @hide
+     */
+    public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
+
+    /**
      * Sent by ConnectivityService to the NetworkAgent to inform the agent of the
      * networks status - whether we could use the network or could not, due to
      * either a bad network configuration (no internet link) or captive portal.
@@ -217,7 +226,13 @@
      * The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}.
      * @hide
      */
-    public static String REDIRECT_URL_KEY = "redirect URL";
+    public static final String REDIRECT_URL_KEY = "redirect URL";
+
+    /**
+     * Bundle key for the underlying networks in {@code EVENT_UNDERLYING_NETWORKS_CHANGED}.
+     * @hide
+     */
+    public static final String UNDERLYING_NETWORKS_KEY = "underlyingNetworks";
 
      /**
      * Sent by the NetworkAgent to ConnectivityService to indicate this network was
@@ -650,6 +665,33 @@
     }
 
     /**
+     * Must be called by the agent when the network's underlying networks change.
+     *
+     * <p>{@code networks} is one of the following:
+     * <ul>
+     * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
+     * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
+     * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear
+     * first in the array.</li>
+     * <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no
+     * underlying network connection, and thus, app traffic will not be sent or received.</li>
+     * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
+     * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
+     * APIs mentioned above to send traffic over specific channels.</li>
+     * </ul>
+     *
+     * @param underlyingNetworks the new list of underlying networks.
+     * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])}
+     */
+    public final void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) {
+        final ArrayList<Network> underlyingArray = (underlyingNetworks != null)
+                ? new ArrayList<>(underlyingNetworks) : null;
+        final Bundle bundle = new Bundle();
+        bundle.putParcelableArrayList(UNDERLYING_NETWORKS_KEY, underlyingArray);
+        queueOrSendMessage(EVENT_UNDERLYING_NETWORKS_CHANGED, bundle);
+    }
+
+    /**
      * Inform ConnectivityService that this agent has now connected.
      * Call {@link #unregister} to disconnect.
      */
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 40bb8bf..8dad11f 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -712,6 +712,7 @@
         if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
             setAdministratorUids(new int[] {creatorUid});
         }
+        // There is no need to clear the UIDs, they have already been cleared by clearAll() above.
     }
 
     /**
@@ -805,7 +806,9 @@
      */
     private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST
             // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
-            | 1 << TRANSPORT_ETHERNET;
+            | 1 << TRANSPORT_ETHERNET
+            // Test VPN networks can be created but their UID ranges must be empty.
+            | 1 << TRANSPORT_VPN;
 
     /**
      * Adds the given transport type to this {@code NetworkCapability} instance.
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index d31218d..a17a498 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -51,13 +51,6 @@
     public static final int ID_NONE = -1;
 
     /**
-     * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
-     * provider, so they use this constant for clarity instead of NONE.
-     * @hide only used by ConnectivityService.
-     */
-    public static final int ID_VPN = -2;
-
-    /**
      * The first providerId value that will be allocated.
      * @hide only used by ConnectivityService.
      */
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 4e019cf..fa65061 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -597,10 +597,17 @@
     }
 
     /**
-     * Return the number of packets transmitted on the specified interface since
-     * device boot. Statistics are measured at the network layer, so both TCP and
+     * Return the number of packets transmitted on the specified interface since the interface
+     * was created. Statistics are measured at the network layer, so both TCP and
      * UDP usage are included.
      *
+     * Note that the returned values are partial statistics that do not count data from several
+     * sources and do not apply several adjustments that are necessary for correctness, such
+     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
+     * determine whether traffic is being transferred on the specific interface but are not a
+     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
+     * APIs.
+     *
      * @param iface The name of the interface.
      * @return The number of transmitted packets.
      */
@@ -613,10 +620,17 @@
     }
 
     /**
-     * Return the number of packets received on the specified interface since
-     * device boot. Statistics are measured at the network layer, so both TCP
+     * Return the number of packets received on the specified interface since the interface was
+     * created. Statistics are measured at the network layer, so both TCP
      * and UDP usage are included.
      *
+     * Note that the returned values are partial statistics that do not count data from several
+     * sources and do not apply several adjustments that are necessary for correctness, such
+     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
+     * determine whether traffic is being transferred on the specific interface but are not a
+     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
+     * APIs.
+     *
      * @param iface The name of the interface.
      * @return The number of received packets.
      */
@@ -628,9 +642,22 @@
         }
     }
 
-    /** {@hide} */
-    @UnsupportedAppUsage
-    public static long getTxBytes(String iface) {
+    /**
+     * Return the number of bytes transmitted on the specified interface since the interface
+     * was created. Statistics are measured at the network layer, so both TCP and
+     * UDP usage are included.
+     *
+     * Note that the returned values are partial statistics that do not count data from several
+     * sources and do not apply several adjustments that are necessary for correctness, such
+     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
+     * determine whether traffic is being transferred on the specific interface but are not a
+     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
+     * APIs.
+     *
+     * @param iface The name of the interface.
+     * @return The number of transmitted bytes.
+     */
+    public static long getTxBytes(@NonNull String iface) {
         try {
             return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES);
         } catch (RemoteException e) {
@@ -638,9 +665,22 @@
         }
     }
 
-    /** {@hide} */
-    @UnsupportedAppUsage
-    public static long getRxBytes(String iface) {
+    /**
+     * Return the number of bytes received on the specified interface since the interface
+     * was created. Statistics are measured at the network layer, so both TCP
+     * and UDP usage are included.
+     *
+     * Note that the returned values are partial statistics that do not count data from several
+     * sources and do not apply several adjustments that are necessary for correctness, such
+     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
+     * determine whether traffic is being transferred on the specific interface but are not a
+     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
+     * APIs.
+     *
+     * @param iface The name of the interface.
+     * @return The number of received bytes.
+     */
+    public static long getRxBytes(@NonNull String iface) {
         try {
             return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES);
         } catch (RemoteException e) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 00023a5..9c2ae4e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2481,6 +2481,29 @@
         "group", "compl", "dorm", "uninit"
     };
 
+    /**
+     * Returned value if energy data is unavailable
+     *
+     * {@hide}
+     */
+    public static final long ENERGY_DATA_UNAVAILABLE = -1;
+
+    /**
+     * Returns the energy in microjoules that the screen consumed while on.
+     * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+     *
+     * {@hide}
+     */
+    public abstract long getScreenOnEnergy();
+
+    /**
+     * Returns the energy in microjoules that the screen consumed while in doze
+     * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+     *
+     * {@hide}
+     */
+    public abstract long getScreenDozeEnergy();
+
     public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS = new BitDescription[] {
         new BitDescription(HistoryItem.STATE_CPU_RUNNING_FLAG, "running", "r"),
         new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
diff --git a/core/java/android/os/ParcelableHolder.java b/core/java/android/os/ParcelableHolder.java
index 95c07b6..fb9fa10 100644
--- a/core/java/android/os/ParcelableHolder.java
+++ b/core/java/android/os/ParcelableHolder.java
@@ -170,16 +170,21 @@
 
         mParcelable = null;
 
+        int dataSize = parcel.readInt();
+        if (dataSize < 0) {
+            throw new IllegalArgumentException("dataSize from parcel is negative");
+        } else if (dataSize == 0) {
+            if (mParcel != null) {
+                mParcel.recycle();
+                mParcel = null;
+            }
+            return;
+        }
         if (mParcel == null) {
             mParcel = Parcel.obtain();
         }
         mParcel.setDataPosition(0);
         mParcel.setDataSize(0);
-
-        int dataSize = parcel.readInt();
-        if (dataSize < 0) {
-            throw new IllegalArgumentException("dataSize from parcel is negative");
-        }
         int dataStartPos = parcel.dataPosition();
 
         mParcel.appendFrom(parcel, dataStartPos, dataSize);
@@ -196,6 +201,11 @@
             return;
         }
 
+        if (mParcelable == null) {
+            parcel.writeInt(0);
+            return;
+        }
+
         int sizePos = parcel.dataPosition();
         parcel.writeInt(0);
         int dataStartPos = parcel.dataPosition();
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 0f2a9f2..f76eb86 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -1138,8 +1138,7 @@
          *
          * @param primitiveId The primitive to add
          * @param scale The scale to apply to the intensity of the primitive.
-         * @param delay The amount of time, in milliseconds, to wait between playing the prior
-         *              primitive and this one
+         * @param delay The amount of time in milliseconds to wait before playing this primitive
          * @return The {@link Composition} object to enable adding multiple primitives in one chain.
          */
         @NonNull
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index cfc3e01..870d224 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -156,10 +156,6 @@
     /** {@hide} */
     public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk";
     /** {@hide} */
-    public static final String PROP_ISOLATED_STORAGE = "persist.sys.isolated_storage";
-    /** {@hide} */
-    public static final String PROP_ISOLATED_STORAGE_SNAPSHOT = "sys.isolated_storage_snapshot";
-    /** {@hide} */
     public static final String PROP_FORCED_SCOPED_STORAGE_WHITELIST =
             "forced_scoped_storage_whitelist";
 
@@ -263,10 +259,6 @@
     public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 4;
     /** {@hide} */
     public static final int DEBUG_VIRTUAL_DISK = 1 << 5;
-    /** {@hide} */
-    public static final int DEBUG_ISOLATED_STORAGE_FORCE_ON = 1 << 6;
-    /** {@hide} */
-    public static final int DEBUG_ISOLATED_STORAGE_FORCE_OFF = 1 << 7;
 
     /** {@hide} */
     public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
@@ -1695,16 +1687,13 @@
 
     /**
      * Return if the currently booted device has the "isolated storage" feature
-     * flag enabled. This will eventually be fully enabled in the final
-     * {@link android.os.Build.VERSION_CODES#Q} release.
+     * flag enabled.
      *
      * @hide
      */
     @SystemApi
     public static boolean hasIsolatedStorage() {
-        // Prefer to use snapshot for current boot when available
-        return SystemProperties.getBoolean(PROP_ISOLATED_STORAGE_SNAPSHOT,
-                SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, true));
+        return false;
     }
 
     /**
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 4379ce1..55ba15a 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -28,50 +28,8 @@
  * @hide Only for use within the system server.
  */
 public abstract class StorageManagerInternal {
-
     /**
-     * Policy that influences how external storage is mounted and reported.
-     */
-    public interface ExternalStorageMountPolicy {
-        /**
-         * Gets the external storage mount mode for the given uid.
-         *
-         * @param uid The UID for which to determine mount mode.
-         * @param packageName The package in the UID for making the call.
-         * @return The mount mode.
-         *
-         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_NONE
-         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_DEFAULT
-         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_READ
-         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_WRITE
-         */
-        public int getMountMode(int uid, String packageName);
-
-        /**
-         * Gets whether external storage should be reported to the given UID.
-         *
-         * @param uid The UID for which to determine whether it has external storage.
-         * @param packageName The package in the UID for making the call.
-         * @return Weather to report external storage.
-         * @return True to report the state of external storage, false to
-         *     report it as unmounted.
-         */
-        public boolean hasExternalStorage(int uid, String packageName);
-    }
-
-    /**
-     * Adds a policy for determining how external storage is mounted and reported.
-     * The mount mode is the most conservative result from querying all registered
-     * policies. Similarly, the reported state is the most conservative result from
-     * querying all registered policies.
-     *
-     * @param policy The policy to add.
-     */
-    public abstract void addExternalStoragePolicy(ExternalStorageMountPolicy policy);
-
-    /**
-     * Gets the mount mode to use for a given UID as determined by consultin all
-     * policies.
+     * Gets the mount mode to use for a given UID
      *
      * @param uid The UID for which to get mount mode.
      * @param packageName The package in the UID for making the call.
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 901494b..237a9f2 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -200,6 +200,21 @@
         internalPath = parcel.readString8();
     }
 
+    public VolumeInfo(VolumeInfo volumeInfo) {
+        this.id = volumeInfo.id;
+        this.type = volumeInfo.type;
+        this.disk = volumeInfo.disk;
+        this.partGuid = volumeInfo.partGuid;
+        this.mountFlags = volumeInfo.mountFlags;
+        this.mountUserId = volumeInfo.mountUserId;
+        this.state = volumeInfo.state;
+        this.fsType = volumeInfo.fsType;
+        this.fsUuid = volumeInfo.fsUuid;
+        this.fsLabel = volumeInfo.fsLabel;
+        this.path = volumeInfo.path;
+        this.internalPath = volumeInfo.internalPath;
+    }
+
     @UnsupportedAppUsage
     public static @NonNull String getEnvironmentForState(int state) {
         final String envState = sStateToEnvironment.get(state);
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 714bcea..44cc0f5 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -451,6 +451,22 @@
             "connectivity_thermal_power_manager";
 
     /**
+     * Namespace for all statsd native features that can be applied immediately.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
+
+    /**
+     * Namespace for all statsd native features that are applied on boot.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
+
+    /**
      * Namespace for configuration related features.
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 884f8cc..249a781 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13286,16 +13286,6 @@
                 "storage_settings_clobber_threshold";
 
         /**
-         * If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link Secure#LOCATION_MODE_OFF}
-         * temporarily for all users.
-         *
-         * @hide
-         */
-        @TestApi
-        public static final String LOCATION_GLOBAL_KILL_SWITCH =
-                "location_global_kill_switch";
-
-        /**
          * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
          * and restoring to lower version of platform API will be skipped.
          *
@@ -13415,11 +13405,6 @@
         public static final String MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY =
                 "max_sound_trigger_detection_service_ops_per_day";
 
-        /** {@hide} */
-        public static final String ISOLATED_STORAGE_LOCAL = "isolated_storage_local";
-        /** {@hide} */
-        public static final String ISOLATED_STORAGE_REMOTE = "isolated_storage_remote";
-
         /**
          * Indicates whether aware is available in the current location.
          * @hide
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index e32ffa6..6ef9e7e 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -16,6 +16,19 @@
 
 package android.security.keymaster;
 
+import android.hardware.keymint.Algorithm;
+import android.hardware.keymint.BlockMode;
+import android.hardware.keymint.Digest;
+import android.hardware.keymint.ErrorCode;
+import android.hardware.keymint.HardwareAuthenticatorType;
+import android.hardware.keymint.KeyFormat;
+import android.hardware.keymint.KeyOrigin;
+import android.hardware.keymint.KeyPurpose;
+import android.hardware.keymint.PaddingMode;
+import android.hardware.keymint.SecurityLevel;
+import android.hardware.keymint.Tag;
+import android.hardware.keymint.TagType;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -30,204 +43,284 @@
     private KeymasterDefs() {}
 
     // Tag types.
-    public static final int KM_INVALID = 0 << 28;
-    public static final int KM_ENUM = 1 << 28;
-    public static final int KM_ENUM_REP = 2 << 28;
-    public static final int KM_UINT = 3 << 28;
-    public static final int KM_UINT_REP = 4 << 28;
-    public static final int KM_ULONG = 5 << 28;
-    public static final int KM_DATE = 6 << 28;
-    public static final int KM_BOOL = 7 << 28;
-    public static final int KM_BIGNUM = 8 << 28;
-    public static final int KM_BYTES = 9 << 28;
-    public static final int KM_ULONG_REP = 10 << 28;
+    public static final int KM_INVALID = TagType.INVALID;
+    public static final int KM_ENUM = TagType.ENUM;
+    public static final int KM_ENUM_REP = TagType.ENUM_REP;
+    public static final int KM_UINT = TagType.UINT;
+    public static final int KM_UINT_REP = TagType.UINT_REP;
+    public static final int KM_ULONG = TagType.ULONG;
+    public static final int KM_DATE = TagType.DATE;
+    public static final int KM_BOOL = TagType.BOOL;
+    public static final int KM_BIGNUM = TagType.BIGNUM;
+    public static final int KM_BYTES = TagType.BYTES;
+    public static final int KM_ULONG_REP = TagType.ULONG_REP;
 
     // Tag values.
-    public static final int KM_TAG_INVALID = KM_INVALID | 0;
-    public static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
-    public static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
-    public static final int KM_TAG_KEY_SIZE = KM_UINT | 3;
-    public static final int KM_TAG_BLOCK_MODE = KM_ENUM_REP | 4;
-    public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
-    public static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
-    public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 7;
-    public static final int KM_TAG_MIN_MAC_LENGTH = KM_UINT | 8;
+    public static final int KM_TAG_INVALID = Tag.INVALID; // KM_INVALID | 0;
+    public static final int KM_TAG_PURPOSE = Tag.PURPOSE; // KM_ENUM_REP | 1;
+    public static final int KM_TAG_ALGORITHM = Tag.ALGORITHM; // KM_ENUM | 2;
+    public static final int KM_TAG_KEY_SIZE = Tag.KEY_SIZE; // KM_UINT | 3;
+    public static final int KM_TAG_BLOCK_MODE = Tag.BLOCK_MODE; // KM_ENUM_REP | 4;
+    public static final int KM_TAG_DIGEST = Tag.DIGEST; // KM_ENUM_REP | 5;
+    public static final int KM_TAG_PADDING = Tag.PADDING; // KM_ENUM_REP | 6;
+    public static final int KM_TAG_CALLER_NONCE = Tag.CALLER_NONCE; // KM_BOOL | 7;
+    public static final int KM_TAG_MIN_MAC_LENGTH = Tag.MIN_MAC_LENGTH; // KM_UINT | 8;
 
-    public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
-    public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
-    public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
+    public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS =
+            Tag.BLOB_USAGE_REQUIREMENTS; // KM_ENUM | 705;
 
-    public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200;
-    public static final int KM_TAG_INCLUDE_UNIQUE_ID = KM_BOOL | 202;
+    public static final int KM_TAG_RSA_PUBLIC_EXPONENT = Tag.RSA_PUBLIC_EXPONENT; // KM_ULONG | 200;
+    public static final int KM_TAG_INCLUDE_UNIQUE_ID = Tag.INCLUDE_UNIQUE_ID; // KM_BOOL | 202;
 
-    public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
-    public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
-    public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
-    public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_UINT | 403;
-    public static final int KM_TAG_MAX_USES_PER_BOOT = KM_UINT | 404;
+    public static final int KM_TAG_ACTIVE_DATETIME = Tag.ACTIVE_DATETIME; // KM_DATE | 400;
+    public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME =
+            Tag.ORIGINATION_EXPIRE_DATETIME; // KM_DATE | 401;
+    public static final int KM_TAG_USAGE_EXPIRE_DATETIME =
+            Tag.USAGE_EXPIRE_DATETIME; // KM_DATE | 402;
+    public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS =
+            Tag.MIN_SECONDS_BETWEEN_OPS; // KM_UINT | 403;
+    public static final int KM_TAG_MAX_USES_PER_BOOT = Tag.MAX_USES_PER_BOOT; // KM_UINT | 404;
 
-    public static final int KM_TAG_ALL_USERS = KM_BOOL | 500;
-    public static final int KM_TAG_USER_ID = KM_UINT | 501;
-    public static final int KM_TAG_USER_SECURE_ID = KM_ULONG_REP | 502;
-    public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
-    public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
-    public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
-    public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
-    public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
-    public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
-    public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
+    public static final int KM_TAG_USER_ID = Tag.USER_ID; // KM_UINT | 501;
+    public static final int KM_TAG_USER_SECURE_ID = Tag.USER_SECURE_ID; // KM_ULONG_REP | 502;
+    public static final int KM_TAG_NO_AUTH_REQUIRED = Tag.NO_AUTH_REQUIRED; // KM_BOOL | 503;
+    public static final int KM_TAG_USER_AUTH_TYPE = Tag.USER_AUTH_TYPE; // KM_ENUM | 504;
+    public static final int KM_TAG_AUTH_TIMEOUT = Tag.AUTH_TIMEOUT; // KM_UINT | 505;
+    public static final int KM_TAG_ALLOW_WHILE_ON_BODY = Tag.ALLOW_WHILE_ON_BODY; // KM_BOOL | 506;
+    public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED =
+            Tag.TRUSTED_USER_PRESENCE_REQUIRED; // KM_BOOL | 507;
+    public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED =
+            Tag.TRUSTED_CONFIRMATION_REQUIRED; // KM_BOOL | 508;
+    public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED =
+            Tag.UNLOCKED_DEVICE_REQUIRED; // KM_BOOL | 509;
 
-    public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
-    public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
+    public static final int KM_TAG_APPLICATION_ID = Tag.APPLICATION_ID; // KM_BYTES | 601;
 
-    public static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
-    public static final int KM_TAG_ORIGIN = KM_ENUM | 702;
-    public static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
-    public static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
-    public static final int KM_TAG_UNIQUE_ID = KM_BYTES | 707;
-    public static final int KM_TAG_ATTESTATION_CHALLENGE = KM_BYTES | 708;
-    public static final int KM_TAG_ATTESTATION_ID_BRAND = KM_BYTES | 710;
-    public static final int KM_TAG_ATTESTATION_ID_DEVICE = KM_BYTES | 711;
-    public static final int KM_TAG_ATTESTATION_ID_PRODUCT = KM_BYTES | 712;
-    public static final int KM_TAG_ATTESTATION_ID_SERIAL = KM_BYTES | 713;
-    public static final int KM_TAG_ATTESTATION_ID_IMEI = KM_BYTES | 714;
-    public static final int KM_TAG_ATTESTATION_ID_MEID = KM_BYTES | 715;
-    public static final int KM_TAG_ATTESTATION_ID_MANUFACTURER = KM_BYTES | 716;
-    public static final int KM_TAG_ATTESTATION_ID_MODEL = KM_BYTES | 717;
-    public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION = KM_BOOL | 720;
+    public static final int KM_TAG_CREATION_DATETIME = Tag.CREATION_DATETIME; // KM_DATE | 701;
+    public static final int KM_TAG_ORIGIN = Tag.ORIGIN; // KM_ENUM | 702;
+    public static final int KM_TAG_ROLLBACK_RESISTANT = Tag.ROLLBACK_RESISTANCE; // KM_BOOL | 703;
+    public static final int KM_TAG_ROOT_OF_TRUST = Tag.ROOT_OF_TRUST; // KM_BYTES | 704;
+    public static final int KM_TAG_UNIQUE_ID = Tag.UNIQUE_ID; // KM_BYTES | 707;
+    public static final int KM_TAG_ATTESTATION_CHALLENGE =
+            Tag.ATTESTATION_CHALLENGE; // KM_BYTES | 708;
+    public static final int KM_TAG_ATTESTATION_ID_BRAND =
+            Tag.ATTESTATION_ID_BRAND; // KM_BYTES | 710;
+    public static final int KM_TAG_ATTESTATION_ID_DEVICE =
+            Tag.ATTESTATION_ID_DEVICE; // KM_BYTES | 711;
+    public static final int KM_TAG_ATTESTATION_ID_PRODUCT =
+            Tag.ATTESTATION_ID_PRODUCT; // KM_BYTES | 712;
+    public static final int KM_TAG_ATTESTATION_ID_SERIAL =
+            Tag.ATTESTATION_ID_SERIAL; // KM_BYTES | 713;
+    public static final int KM_TAG_ATTESTATION_ID_IMEI =
+            Tag.ATTESTATION_ID_IMEI; // KM_BYTES | 714;
+    public static final int KM_TAG_ATTESTATION_ID_MEID =
+            Tag.ATTESTATION_ID_MEID; // KM_BYTES | 715;
+    public static final int KM_TAG_ATTESTATION_ID_MANUFACTURER =
+            Tag.ATTESTATION_ID_MANUFACTURER; // KM_BYTES | 716;
+    public static final int KM_TAG_ATTESTATION_ID_MODEL =
+            Tag.ATTESTATION_ID_MODEL; // KM_BYTES | 717;
+    public static final int KM_TAG_VENDOR_PATCHLEVEL =
+            Tag.VENDOR_PATCHLEVEL; // KM_UINT | 718;
+    public static final int KM_TAG_BOOT_PATCHLEVEL =
+            Tag.BOOT_PATCHLEVEL; // KM_UINT | 719;
+    public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION =
+            Tag.DEVICE_UNIQUE_ATTESTATION; // KM_BOOL | 720;
 
-    public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
-    public static final int KM_TAG_NONCE = KM_BYTES | 1001;
-    public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1002;
-    public static final int KM_TAG_MAC_LENGTH = KM_UINT | 1003;
+    public static final int KM_TAG_ASSOCIATED_DATA = Tag.ASSOCIATED_DATA; // KM_BYTES | 1000;
+    public static final int KM_TAG_NONCE = Tag.NONCE; // KM_BYTES | 1001;
+    public static final int KM_TAG_MAC_LENGTH = Tag.MAC_LENGTH; // KM_UINT | 1003;
 
     // Algorithm values.
-    public static final int KM_ALGORITHM_RSA = 1;
-    public static final int KM_ALGORITHM_EC = 3;
-    public static final int KM_ALGORITHM_AES = 32;
-    public static final int KM_ALGORITHM_3DES = 33;
-    public static final int KM_ALGORITHM_HMAC = 128;
+    public static final int KM_ALGORITHM_RSA = Algorithm.RSA;
+    public static final int KM_ALGORITHM_EC = Algorithm.EC;
+    public static final int KM_ALGORITHM_AES = Algorithm.AES;
+    public static final int KM_ALGORITHM_3DES = Algorithm.TRIPLE_DES;
+    public static final int KM_ALGORITHM_HMAC = Algorithm.HMAC;
 
     // Block modes.
-    public static final int KM_MODE_ECB = 1;
-    public static final int KM_MODE_CBC = 2;
-    public static final int KM_MODE_CTR = 3;
-    public static final int KM_MODE_GCM = 32;
+    public static final int KM_MODE_ECB = BlockMode.ECB;
+    public static final int KM_MODE_CBC = BlockMode.CBC;
+    public static final int KM_MODE_CTR = BlockMode.CTR;
+    public static final int KM_MODE_GCM = BlockMode.GCM;
 
     // Padding modes.
-    public static final int KM_PAD_NONE = 1;
-    public static final int KM_PAD_RSA_OAEP = 2;
-    public static final int KM_PAD_RSA_PSS = 3;
-    public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
-    public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
-    public static final int KM_PAD_PKCS7 = 64;
+    public static final int KM_PAD_NONE = PaddingMode.NONE;
+    public static final int KM_PAD_RSA_OAEP = PaddingMode.RSA_OAEP;
+    public static final int KM_PAD_RSA_PSS = PaddingMode.RSA_PSS;
+    public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = PaddingMode.RSA_PKCS1_1_5_ENCRYPT;
+    public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = PaddingMode.RSA_PKCS1_1_5_SIGN;
+    public static final int KM_PAD_PKCS7 = PaddingMode.PKCS7;
 
     // Digest modes.
-    public static final int KM_DIGEST_NONE = 0;
-    public static final int KM_DIGEST_MD5 = 1;
-    public static final int KM_DIGEST_SHA1 = 2;
-    public static final int KM_DIGEST_SHA_2_224 = 3;
-    public static final int KM_DIGEST_SHA_2_256 = 4;
-    public static final int KM_DIGEST_SHA_2_384 = 5;
-    public static final int KM_DIGEST_SHA_2_512 = 6;
+    public static final int KM_DIGEST_NONE = Digest.NONE;
+    public static final int KM_DIGEST_MD5 = Digest.MD5;
+    public static final int KM_DIGEST_SHA1 = Digest.SHA1;
+    public static final int KM_DIGEST_SHA_2_224 = Digest.SHA_2_224;
+    public static final int KM_DIGEST_SHA_2_256 = Digest.SHA_2_256;
+    public static final int KM_DIGEST_SHA_2_384 = Digest.SHA_2_384;
+    public static final int KM_DIGEST_SHA_2_512 = Digest.SHA_2_512;
 
     // Key origins.
-    public static final int KM_ORIGIN_GENERATED = 0;
-    public static final int KM_ORIGIN_IMPORTED = 2;
-    public static final int KM_ORIGIN_UNKNOWN = 3;
-    public static final int KM_ORIGIN_SECURELY_IMPORTED = 4;
+    public static final int KM_ORIGIN_GENERATED = KeyOrigin.GENERATED;
+    public static final int KM_ORIGIN_DERIVED = KeyOrigin.DERIVED;
+    public static final int KM_ORIGIN_IMPORTED = KeyOrigin.IMPORTED;
+    public static final int KM_ORIGIN_UNKNOWN = KeyOrigin.RESERVED;
+    public static final int KM_ORIGIN_SECURELY_IMPORTED = KeyOrigin.SECURELY_IMPORTED;
 
     // Key usability requirements.
     public static final int KM_BLOB_STANDALONE = 0;
     public static final int KM_BLOB_REQUIRES_FILE_SYSTEM = 1;
 
     // Operation Purposes.
-    public static final int KM_PURPOSE_ENCRYPT = 0;
-    public static final int KM_PURPOSE_DECRYPT = 1;
-    public static final int KM_PURPOSE_SIGN = 2;
-    public static final int KM_PURPOSE_VERIFY = 3;
-    public static final int KM_PURPOSE_WRAP = 5;
+    public static final int KM_PURPOSE_ENCRYPT = KeyPurpose.ENCRYPT;
+    public static final int KM_PURPOSE_DECRYPT = KeyPurpose.DECRYPT;
+    public static final int KM_PURPOSE_SIGN = KeyPurpose.SIGN;
+    public static final int KM_PURPOSE_VERIFY = KeyPurpose.VERIFY;
+    public static final int KM_PURPOSE_WRAP = KeyPurpose.WRAP_KEY;
 
     // Key formats.
-    public static final int KM_KEY_FORMAT_X509 = 0;
-    public static final int KM_KEY_FORMAT_PKCS8 = 1;
-    public static final int KM_KEY_FORMAT_RAW = 3;
+    public static final int KM_KEY_FORMAT_X509 = KeyFormat.X509;
+    public static final int KM_KEY_FORMAT_PKCS8 = KeyFormat.PKCS8;
+    public static final int KM_KEY_FORMAT_RAW = KeyFormat.RAW;
 
     // User authenticators.
-    public static final int HW_AUTH_PASSWORD = 1 << 0;
-    public static final int HW_AUTH_BIOMETRIC = 1 << 1;
+    public static final int HW_AUTH_PASSWORD = HardwareAuthenticatorType.PASSWORD;
+    public static final int HW_AUTH_BIOMETRIC = HardwareAuthenticatorType.FINGERPRINT;
 
     // Security Levels.
-    public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
-    public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
-    public static final int KM_SECURITY_LEVEL_STRONGBOX = 2;
+    public static final int KM_SECURITY_LEVEL_SOFTWARE = SecurityLevel.SOFTWARE;
+    public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT =
+            SecurityLevel.TRUSTED_ENVIRONMENT;
+    public static final int KM_SECURITY_LEVEL_STRONGBOX = SecurityLevel.STRONGBOX;
 
     // Error codes.
-    public static final int KM_ERROR_OK = 0;
-    public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1;
-    public static final int KM_ERROR_UNSUPPORTED_PURPOSE = -2;
-    public static final int KM_ERROR_INCOMPATIBLE_PURPOSE = -3;
-    public static final int KM_ERROR_UNSUPPORTED_ALGORITHM = -4;
-    public static final int KM_ERROR_INCOMPATIBLE_ALGORITHM = -5;
-    public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE = -6;
-    public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7;
-    public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8;
-    public static final int KM_ERROR_UNSUPPORTED_MAC_LENGTH = -9;
-    public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE = -10;
-    public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11;
-    public static final int KM_ERROR_UNSUPPORTED_DIGEST = -12;
-    public static final int KM_ERROR_INCOMPATIBLE_DIGEST = -13;
-    public static final int KM_ERROR_INVALID_EXPIRATION_TIME = -14;
-    public static final int KM_ERROR_INVALID_USER_ID = -15;
-    public static final int KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT = -16;
-    public static final int KM_ERROR_UNSUPPORTED_KEY_FORMAT = -17;
-    public static final int KM_ERROR_INCOMPATIBLE_KEY_FORMAT = -18;
-    public static final int KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19;
-    public static final int KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20;
-    public static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
-    public static final int KM_ERROR_KEY_EXPORT_OPTIONS_INVALID = -22;
-    public static final int KM_ERROR_DELEGATION_NOT_ALLOWED = -23;
-    public static final int KM_ERROR_KEY_NOT_YET_VALID = -24;
-    public static final int KM_ERROR_KEY_EXPIRED = -25;
-    public static final int KM_ERROR_KEY_USER_NOT_AUTHENTICATED = -26;
-    public static final int KM_ERROR_OUTPUT_PARAMETER_NULL = -27;
-    public static final int KM_ERROR_INVALID_OPERATION_HANDLE = -28;
-    public static final int KM_ERROR_INSUFFICIENT_BUFFER_SPACE = -29;
-    public static final int KM_ERROR_VERIFICATION_FAILED = -30;
-    public static final int KM_ERROR_TOO_MANY_OPERATIONS = -31;
-    public static final int KM_ERROR_UNEXPECTED_NULL_POINTER = -32;
-    public static final int KM_ERROR_INVALID_KEY_BLOB = -33;
-    public static final int KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED = -34;
-    public static final int KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED = -35;
-    public static final int KM_ERROR_IMPORTED_KEY_NOT_SIGNED = -36;
-    public static final int KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED = -37;
-    public static final int KM_ERROR_INVALID_ARGUMENT = -38;
-    public static final int KM_ERROR_UNSUPPORTED_TAG = -39;
-    public static final int KM_ERROR_INVALID_TAG = -40;
-    public static final int KM_ERROR_MEMORY_ALLOCATION_FAILED = -41;
-    public static final int KM_ERROR_INVALID_RESCOPING = -42;
-    public static final int KM_ERROR_IMPORT_PARAMETER_MISMATCH = -44;
-    public static final int KM_ERROR_SECURE_HW_ACCESS_DENIED = -45;
-    public static final int KM_ERROR_OPERATION_CANCELLED = -46;
-    public static final int KM_ERROR_CONCURRENT_ACCESS_CONFLICT = -47;
-    public static final int KM_ERROR_SECURE_HW_BUSY = -48;
-    public static final int KM_ERROR_SECURE_HW_COMMUNICATION_FAILED = -49;
-    public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50;
-    public static final int KM_ERROR_MISSING_NONCE = -51;
-    public static final int KM_ERROR_INVALID_NONCE = -52;
-    public static final int KM_ERROR_MISSING_MAC_LENGTH = -53;
-    public static final int KM_ERROR_KEY_RATE_LIMIT_EXCEEDED = -54;
-    public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55;
-    public static final int KM_ERROR_KEY_MAX_OPS_EXCEEDED = -56;
-    public static final int KM_ERROR_INVALID_MAC_LENGTH = -57;
-    public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
-    public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
-    public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
-    public static final int KM_ERROR_HARDWARE_TYPE_UNAVAILABLE = -68;
-    public static final int KM_ERROR_DEVICE_LOCKED = -72;
-    public static final int KM_ERROR_UNIMPLEMENTED = -100;
-    public static final int KM_ERROR_VERSION_MISMATCH = -101;
-    public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
+    public static final int KM_ERROR_OK = ErrorCode.OK;
+    public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET =
+            ErrorCode.ROOT_OF_TRUST_ALREADY_SET; // -1;
+    public static final int KM_ERROR_UNSUPPORTED_PURPOSE =
+            ErrorCode.UNSUPPORTED_PURPOSE; // -2;
+    public static final int KM_ERROR_INCOMPATIBLE_PURPOSE =
+            ErrorCode.INCOMPATIBLE_PURPOSE; // -3;
+    public static final int KM_ERROR_UNSUPPORTED_ALGORITHM =
+            ErrorCode.UNSUPPORTED_ALGORITHM; // -4;
+    public static final int KM_ERROR_INCOMPATIBLE_ALGORITHM =
+            ErrorCode.INCOMPATIBLE_ALGORITHM; // -5;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE =
+            ErrorCode.UNSUPPORTED_KEY_SIZE; // -6;
+    public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE =
+            ErrorCode.UNSUPPORTED_BLOCK_MODE; // -7;
+    public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE =
+            ErrorCode.INCOMPATIBLE_BLOCK_MODE; // -8;
+    public static final int KM_ERROR_UNSUPPORTED_MAC_LENGTH =
+            ErrorCode.UNSUPPORTED_MAC_LENGTH; // -9;
+    public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE =
+            ErrorCode.UNSUPPORTED_PADDING_MODE; // -10;
+    public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE =
+            ErrorCode.INCOMPATIBLE_PADDING_MODE; // -11;
+    public static final int KM_ERROR_UNSUPPORTED_DIGEST =
+            ErrorCode.UNSUPPORTED_DIGEST; // -12;
+    public static final int KM_ERROR_INCOMPATIBLE_DIGEST =
+            ErrorCode.INCOMPATIBLE_DIGEST; // -13;
+    public static final int KM_ERROR_INVALID_EXPIRATION_TIME =
+            ErrorCode.INVALID_EXPIRATION_TIME; // -14;
+    public static final int KM_ERROR_INVALID_USER_ID =
+            ErrorCode.INVALID_USER_ID; // -15;
+    public static final int KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT =
+            ErrorCode.INVALID_AUTHORIZATION_TIMEOUT; // -16;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_FORMAT =
+            ErrorCode.UNSUPPORTED_KEY_FORMAT; // -17;
+    public static final int KM_ERROR_INCOMPATIBLE_KEY_FORMAT =
+            ErrorCode.INCOMPATIBLE_KEY_FORMAT; // -18;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM =
+            ErrorCode.UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM; // -19;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM =
+            ErrorCode.UNSUPPORTED_KEY_VERIFICATION_ALGORITHM; // -20;
+    public static final int KM_ERROR_INVALID_INPUT_LENGTH =
+            ErrorCode.INVALID_INPUT_LENGTH; // -21;
+    public static final int KM_ERROR_KEY_EXPORT_OPTIONS_INVALID =
+            ErrorCode.KEY_EXPORT_OPTIONS_INVALID; // -22;
+    public static final int KM_ERROR_DELEGATION_NOT_ALLOWED =
+            ErrorCode.DELEGATION_NOT_ALLOWED; // -23;
+    public static final int KM_ERROR_KEY_NOT_YET_VALID =
+            ErrorCode.KEY_NOT_YET_VALID; // -24;
+    public static final int KM_ERROR_KEY_EXPIRED =
+            ErrorCode.KEY_EXPIRED; // -25;
+    public static final int KM_ERROR_KEY_USER_NOT_AUTHENTICATED =
+            ErrorCode.KEY_USER_NOT_AUTHENTICATED; // -26;
+    public static final int KM_ERROR_OUTPUT_PARAMETER_NULL =
+            ErrorCode.OUTPUT_PARAMETER_NULL; // -27;
+    public static final int KM_ERROR_INVALID_OPERATION_HANDLE =
+            ErrorCode.INVALID_OPERATION_HANDLE; // -28;
+    public static final int KM_ERROR_INSUFFICIENT_BUFFER_SPACE =
+            ErrorCode.INSUFFICIENT_BUFFER_SPACE; // -29;
+    public static final int KM_ERROR_VERIFICATION_FAILED =
+            ErrorCode.VERIFICATION_FAILED; // -30;
+    public static final int KM_ERROR_TOO_MANY_OPERATIONS =
+            ErrorCode.TOO_MANY_OPERATIONS; // -31;
+    public static final int KM_ERROR_UNEXPECTED_NULL_POINTER =
+            ErrorCode.UNEXPECTED_NULL_POINTER; // -32;
+    public static final int KM_ERROR_INVALID_KEY_BLOB =
+            ErrorCode.INVALID_KEY_BLOB; // -33;
+    public static final int KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED =
+            ErrorCode.IMPORTED_KEY_NOT_ENCRYPTED; // -34;
+    public static final int KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED =
+            ErrorCode.IMPORTED_KEY_DECRYPTION_FAILED; // -35;
+    public static final int KM_ERROR_IMPORTED_KEY_NOT_SIGNED =
+            ErrorCode.IMPORTED_KEY_NOT_SIGNED; // -36;
+    public static final int KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED =
+            ErrorCode.IMPORTED_KEY_VERIFICATION_FAILED; // -37;
+    public static final int KM_ERROR_INVALID_ARGUMENT =
+            ErrorCode.INVALID_ARGUMENT; // -38;
+    public static final int KM_ERROR_UNSUPPORTED_TAG =
+            ErrorCode.UNSUPPORTED_TAG; // -39;
+    public static final int KM_ERROR_INVALID_TAG =
+            ErrorCode.INVALID_TAG; // -40;
+    public static final int KM_ERROR_MEMORY_ALLOCATION_FAILED =
+            ErrorCode.MEMORY_ALLOCATION_FAILED; // -41;
+    public static final int KM_ERROR_IMPORT_PARAMETER_MISMATCH =
+            ErrorCode.IMPORT_PARAMETER_MISMATCH; // -44;
+    public static final int KM_ERROR_SECURE_HW_ACCESS_DENIED =
+            ErrorCode.SECURE_HW_ACCESS_DENIED; // -45;
+    public static final int KM_ERROR_OPERATION_CANCELLED =
+            ErrorCode.OPERATION_CANCELLED; // -46;
+    public static final int KM_ERROR_CONCURRENT_ACCESS_CONFLICT =
+            ErrorCode.CONCURRENT_ACCESS_CONFLICT; // -47;
+    public static final int KM_ERROR_SECURE_HW_BUSY =
+            ErrorCode.SECURE_HW_BUSY; // -48;
+    public static final int KM_ERROR_SECURE_HW_COMMUNICATION_FAILED =
+            ErrorCode.SECURE_HW_COMMUNICATION_FAILED; // -49;
+    public static final int KM_ERROR_UNSUPPORTED_EC_FIELD =
+            ErrorCode.UNSUPPORTED_EC_FIELD; // -50;
+    public static final int KM_ERROR_MISSING_NONCE =
+            ErrorCode.MISSING_NONCE; // -51;
+    public static final int KM_ERROR_INVALID_NONCE =
+            ErrorCode.INVALID_NONCE; // -52;
+    public static final int KM_ERROR_MISSING_MAC_LENGTH =
+            ErrorCode.MISSING_MAC_LENGTH; // -53;
+    public static final int KM_ERROR_KEY_RATE_LIMIT_EXCEEDED =
+            ErrorCode.KEY_RATE_LIMIT_EXCEEDED; // -54;
+    public static final int KM_ERROR_CALLER_NONCE_PROHIBITED =
+            ErrorCode.CALLER_NONCE_PROHIBITED; // -55;
+    public static final int KM_ERROR_KEY_MAX_OPS_EXCEEDED =
+            ErrorCode.KEY_MAX_OPS_EXCEEDED; // -56;
+    public static final int KM_ERROR_INVALID_MAC_LENGTH =
+            ErrorCode.INVALID_MAC_LENGTH; // -57;
+    public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH =
+            ErrorCode.MISSING_MIN_MAC_LENGTH; // -58;
+    public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH =
+            ErrorCode.UNSUPPORTED_MIN_MAC_LENGTH; // -59;
+    public static final int KM_ERROR_CANNOT_ATTEST_IDS =
+            ErrorCode.CANNOT_ATTEST_IDS; // -66;
+    public static final int KM_ERROR_HARDWARE_TYPE_UNAVAILABLE =
+            ErrorCode.HARDWARE_TYPE_UNAVAILABLE; // -68;
+    public static final int KM_ERROR_DEVICE_LOCKED =
+            ErrorCode.DEVICE_LOCKED; // -72;
+    public static final int KM_ERROR_UNIMPLEMENTED =
+            ErrorCode.UNIMPLEMENTED; // -100;
+    public static final int KM_ERROR_VERSION_MISMATCH =
+            ErrorCode.VERSION_MISMATCH; // -101;
+    public static final int KM_ERROR_UNKNOWN_ERROR =
+            ErrorCode.UNKNOWN_ERROR; // -1000;
 
     public static final Map<Integer, String> sErrorCodeToString = new HashMap<Integer, String>();
     static {
diff --git a/core/java/android/service/autofill/TEST_MAPPING b/core/java/android/service/autofill/TEST_MAPPING
new file mode 100644
index 0000000..87a17eb
--- /dev/null
+++ b/core/java/android/service/autofill/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+    {
+      "path": "frameworks/base/services/autofill/java/com/android/server/autofill"
+    }
+  ]
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 9a76f19..3763711 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -199,6 +199,7 @@
         final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
         final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
         private final Point mSurfaceSize = new Point();
+        private final Point mLastSurfaceSize = new Point();
         private final Matrix mTmpMatrix = new Matrix();
         private final float[] mTmpValues = new float[9];
 
@@ -908,6 +909,14 @@
                     if (mSurfaceControl.isValid()) {
                         mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
                     }
+                    if (!mLastSurfaceSize.equals(mSurfaceSize)) {
+                        mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
+                        if (mSurfaceControl != null && mSurfaceControl.isValid()) {
+                            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+                            t.setBufferSize(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y);
+                            t.apply();
+                        }
+                    }
 
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrames);
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index 6d5e830..ece6b35 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -271,6 +271,26 @@
         return res.toString();
     }
 
+    /**
+     * Gets human-readable representation of constants (static final values).
+     *
+     * @hide
+     */
+    public static String constantToString(Class<?> clazz, String prefix, int value) {
+        for (Field field : clazz.getDeclaredFields()) {
+            final int modifiers = field.getModifiers();
+            try {
+                if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
+                        && field.getType().equals(int.class) && field.getName().startsWith(prefix)
+                        && field.getInt(null) == value) {
+                    return constNameWithoutPrefix(prefix, field);
+                }
+            } catch (IllegalAccessException ignored) {
+            }
+        }
+        return prefix + Integer.toString(value);
+    }
+
     private static String constNameWithoutPrefix(String prefix, Field field) {
         return field.getName().substring(prefix.length());
     }
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 3da3184..59299f6 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -276,7 +276,7 @@
     private static float getRefreshRate() {
         DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
                 Display.DEFAULT_DISPLAY);
-        return di.getMode().getRefreshRate();
+        return di.getRefreshRate();
     }
 
     /**
@@ -944,7 +944,7 @@
         private VsyncEventData mLastVsyncEventData = new VsyncEventData();
 
         public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
-            super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
+            super(looper, vsyncSource, 0);
         }
 
         // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
diff --git a/core/java/android/view/ContentInfo.java b/core/java/android/view/ContentInfo.java
new file mode 100644
index 0000000..b58937b
--- /dev/null
+++ b/core/java/android/view/ContentInfo.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ClipData;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/**
+ * Holds all the relevant data for a request to {@link View#performReceiveContent}.
+ */
+public final class ContentInfo {
+
+    /**
+     * Specifies the UI through which content is being inserted. Future versions of Android may
+     * support additional values.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
+            SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Source {}
+
+    /**
+     * Specifies that the operation was triggered by the app that contains the target view.
+     */
+    public static final int SOURCE_APP = 0;
+
+    /**
+     * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
+     * "Paste as plain text" action in the insertion/selection menu).
+     */
+    public static final int SOURCE_CLIPBOARD = 1;
+
+    /**
+     * Specifies that the operation was triggered from the soft keyboard (also known as input
+     * method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
+     * for more info.
+     */
+    public static final int SOURCE_INPUT_METHOD = 2;
+
+    /**
+     * Specifies that the operation was triggered by the drag/drop framework. See
+     * https://developer.android.com/guide/topics/ui/drag-drop for more info.
+     */
+    public static final int SOURCE_DRAG_AND_DROP = 3;
+
+    /**
+     * Specifies that the operation was triggered by the autofill framework. See
+     * https://developer.android.com/guide/topics/text/autofill for more info.
+     */
+    public static final int SOURCE_AUTOFILL = 4;
+
+    /**
+     * Specifies that the operation was triggered by a result from a
+     * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
+     * menu.
+     */
+    public static final int SOURCE_PROCESS_TEXT = 5;
+
+    /**
+     * Returns the symbolic name of the given source.
+     *
+     * @hide
+     */
+    static String sourceToString(@Source int source) {
+        switch (source) {
+            case SOURCE_APP: return "SOURCE_APP";
+            case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
+            case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
+            case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
+            case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
+            case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
+        }
+        return String.valueOf(source);
+    }
+
+    /**
+     * Flags to configure the insertion behavior.
+     *
+     * @hide
+     */
+    @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Flags {}
+
+    /**
+     * Flag requesting that the content should be converted to plain text prior to inserting.
+     */
+    public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
+
+    /**
+     * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
+     *
+     * @hide
+     */
+    static String flagsToString(@Flags int flags) {
+        if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
+            return "FLAG_CONVERT_TO_PLAIN_TEXT";
+        }
+        return String.valueOf(flags);
+    }
+
+    @NonNull
+    private final ClipData mClip;
+    @Source
+    private final int mSource;
+    @Flags
+    private final int mFlags;
+    @Nullable
+    private final Uri mLinkUri;
+    @Nullable
+    private final Bundle mExtras;
+
+    private ContentInfo(Builder b) {
+        this.mClip = Objects.requireNonNull(b.mClip);
+        this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
+                "source");
+        this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
+        this.mLinkUri = b.mLinkUri;
+        this.mExtras = b.mExtras;
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "ContentInfo{"
+                + "clip=" + mClip
+                + ", source=" + sourceToString(mSource)
+                + ", flags=" + flagsToString(mFlags)
+                + ", linkUri=" + mLinkUri
+                + ", extras=" + mExtras
+                + "}";
+    }
+
+    /**
+     * The data to be inserted.
+     */
+    @NonNull
+    public ClipData getClip() {
+        return mClip;
+    }
+
+    /**
+     * The source of the operation. See {@code SOURCE_} constants. Future versions of Android
+     * may pass additional values.
+     */
+    @Source
+    public int getSource() {
+        return mSource;
+    }
+
+    /**
+     * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
+     */
+    @Flags
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Optional http/https URI for the content that may be provided by the IME. This is only
+     * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
+     * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
+     * IME.
+     */
+    @Nullable
+    public Uri getLinkUri() {
+        return mLinkUri;
+    }
+
+    /**
+     * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
+     * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
+     * the IME.
+     */
+    @Nullable
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    /**
+     * Partitions the content based on the given predicate.
+     *
+     * <p>Similar to a
+     * {@link java.util.stream.Collectors#partitioningBy(Predicate) partitioning collector},
+     * this function classifies the content and organizes it into a map, grouping the items that
+     * matched vs didn't match the predicate.
+     *
+     * <p>Except for the {@link ClipData} items, the returned objects will contain all the same
+     * metadata as the original.
+     *
+     * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which
+     * partition to place it into.
+     * @return A map containing the partitioned content. The map will contain a single entry if
+     * all items were classified into the same partition (all matched or all didn't match the
+     * predicate) or two entries (if there's at least one item that matched the predicate and at
+     * least one item that didn't match the predicate).
+     */
+    @NonNull
+    public Map<Boolean, ContentInfo> partition(@NonNull Predicate<ClipData.Item> itemPredicate) {
+        if (mClip.getItemCount() == 1) {
+            Map<Boolean, ContentInfo> result = new ArrayMap<>(1);
+            result.put(itemPredicate.test(mClip.getItemAt(0)), this);
+            return result;
+        }
+        ArrayList<ClipData.Item> accepted = new ArrayList<>();
+        ArrayList<ClipData.Item> remaining = new ArrayList<>();
+        for (int i = 0; i < mClip.getItemCount(); i++) {
+            ClipData.Item item = mClip.getItemAt(i);
+            if (itemPredicate.test(item)) {
+                accepted.add(item);
+            } else {
+                remaining.add(item);
+            }
+        }
+        Map<Boolean, ContentInfo> result = new ArrayMap<>(2);
+        if (!accepted.isEmpty()) {
+            ClipData acceptedClip = new ClipData(mClip.getDescription(), accepted);
+            result.put(true, new Builder(this).setClip(acceptedClip).build());
+        }
+        if (!remaining.isEmpty()) {
+            ClipData remainingClip = new ClipData(mClip.getDescription(), remaining);
+            result.put(false, new Builder(this).setClip(remainingClip).build());
+        }
+        return result;
+    }
+
+    /**
+     * Builder for {@link ContentInfo}.
+     */
+    public static final class Builder {
+        @NonNull
+        private ClipData mClip;
+        @Source
+        private int mSource;
+        @Flags
+        private  int mFlags;
+        @Nullable
+        private Uri mLinkUri;
+        @Nullable
+        private Bundle mExtras;
+
+        /**
+         * Creates a new builder initialized with the data from the given builder.
+         */
+        public Builder(@NonNull ContentInfo other) {
+            mClip = other.mClip;
+            mSource = other.mSource;
+            mFlags = other.mFlags;
+            mLinkUri = other.mLinkUri;
+            mExtras = other.mExtras;
+        }
+
+        /**
+         * Creates a new builder.
+         * @param clip   The data to insert.
+         * @param source The source of the operation. See {@code SOURCE_} constants.
+         */
+        public Builder(@NonNull ClipData clip, @Source int source) {
+            mClip = clip;
+            mSource = source;
+        }
+
+        /**
+         * Sets the data to be inserted.
+         * @param clip The data to insert.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setClip(@NonNull ClipData clip) {
+            mClip = clip;
+            return this;
+        }
+
+        /**
+         * Sets the source of the operation.
+         * @param source The source of the operation. See {@code SOURCE_} constants.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setSource(@Source int source) {
+            mSource = source;
+            return this;
+        }
+
+        /**
+         * Sets flags that control content insertion behavior.
+         * @param flags Optional flags to configure the insertion behavior. Use 0 for default
+         *              behavior. See {@code FLAG_} constants.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setFlags(@Flags int flags) {
+            mFlags = flags;
+            return this;
+        }
+
+        /**
+         * Sets the http/https URI for the content. See
+         * {@link android.view.inputmethod.InputContentInfo#getLinkUri} for more info.
+         * @param linkUri Optional http/https URI for the content.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setLinkUri(@Nullable Uri linkUri) {
+            mLinkUri = linkUri;
+            return this;
+        }
+
+        /**
+         * Sets additional metadata.
+         * @param extras Optional bundle with additional metadata.
+         * @return this builder
+         */
+        @NonNull
+        public Builder setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * @return A new {@link ContentInfo} instance with the data from this builder.
+         */
+        @NonNull
+        public ContentInfo build() {
+            return new ContentInfo(this);
+        }
+    }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 3021aa6a..56c7e27 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -456,6 +456,9 @@
     // TODO (b/114338689): Remove the flag and use WindowManager#REMOVE_CONTENT_MODE_DESTROY
     public static final int REMOVE_MODE_DESTROY_CONTENT = 1;
 
+    /** @hide */
+    public static final int DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE = 0xFF;
+
     /**
      * Internal method to create a display.
      * The display created with this method will have a static {@link DisplayAdjustments} applied.
@@ -886,7 +889,7 @@
     public float getRefreshRate() {
         synchronized (this) {
             updateDisplayInfoLocked();
-            return mDisplayInfo.getMode().getRefreshRate();
+            return mDisplayInfo.getRefreshRate();
         }
     }
 
@@ -1391,6 +1394,23 @@
     }
 
     /**
+     * Returns true if the display is in an off state such as {@link #STATE_OFF}.
+     * @hide
+     */
+    public static boolean isOffState(int state) {
+        return state == STATE_OFF;
+    }
+
+    /**
+     * Returns true if the display is in an on state such as {@link #STATE_ON}
+     * or {@link #STATE_VR} or {@link #STATE_ON_SUSPEND}.
+     * @hide
+     */
+    public static boolean isOnState(int state) {
+        return state == STATE_ON || state == STATE_VR || state == STATE_ON_SUSPEND;
+    }
+
+    /**
      * A mode supported by a given display.
      *
      * @see Display#getSupportedModes()
@@ -1509,6 +1529,16 @@
                     Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate);
         }
 
+        /**
+         * Returns {@code true} if this mode equals to the other mode in all parameters except
+         * the refresh rate.
+         *
+         * @hide
+         */
+        public boolean equalsExceptRefreshRate(@Nullable Display.Mode other) {
+            return mWidth == other.mWidth && mHeight == other.mHeight;
+        }
+
         @Override
         public boolean equals(@Nullable Object other) {
             if (this == other) {
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index e8a4ed4..5d4a4e5 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -23,6 +23,8 @@
 import android.os.MessageQueue;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import dalvik.annotation.optimization.FastNative;
 import dalvik.system.CloseGuard;
 
@@ -56,18 +58,18 @@
     public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;
 
     /**
-     * Specifies to suppress config changed events from being generated from Surface Flinger.
-     * <p>
-     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
-     */
-    public static final int CONFIG_CHANGED_EVENT_SUPPRESS = 0;
-
-    /**
      * Specifies to generate config changed events from Surface Flinger.
      * <p>
      * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
      */
-    public static final int CONFIG_CHANGED_EVENT_DISPATCH = 1;
+    public static final int EVENT_REGISTRATION_CONFIG_CHANGED_FLAG = 0x1;
+
+    /**
+     * Specifies to generate frame rate override events from Surface Flinger.
+     * <p>
+     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
+     */
+    public static final int EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG = 0x2;
 
     private static final String TAG = "DisplayEventReceiver";
 
@@ -81,7 +83,7 @@
     private MessageQueue mMessageQueue;
 
     private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
-            MessageQueue messageQueue, int vsyncSource, int configChanged);
+            MessageQueue messageQueue, int vsyncSource, int eventRegistration);
     private static native void nativeDispose(long receiverPtr);
     @FastNative
     private static native void nativeScheduleVsync(long receiverPtr);
@@ -93,7 +95,7 @@
      */
     @UnsupportedAppUsage
     public DisplayEventReceiver(Looper looper) {
-        this(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_SUPPRESS);
+        this(looper, VSYNC_SOURCE_APP, 0);
     }
 
     /**
@@ -101,17 +103,17 @@
      *
      * @param looper The looper to use when invoking callbacks.
      * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
-     * @param configChanged Whether to dispatch config changed events. Must be one of the
-     * CONFIG_CHANGED_EVENT_* values.
+     * @param eventRegistration Which events to dispatch. Must be a bitfield consist of the
+     * EVENT_REGISTRATION_*_FLAG values.
      */
-    public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {
+    public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
         if (looper == null) {
             throw new IllegalArgumentException("looper must not be null");
         }
 
         mMessageQueue = looper.getQueue();
         mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
-                vsyncSource, configChanged);
+                vsyncSource, eventRegistration);
 
         mCloseGuard.open("dispose");
     }
@@ -206,6 +208,41 @@
     }
 
     /**
+     * Represents a mapping between a UID and an override frame rate
+     */
+    public static class FrameRateOverride {
+        // The application uid
+        public final int uid;
+
+        // The frame rate that this application runs at
+        public final float frameRateHz;
+
+
+        @VisibleForTesting
+        public FrameRateOverride(int uid, float frameRateHz) {
+            this.uid = uid;
+            this.frameRateHz = frameRateHz;
+        }
+
+        @Override
+        public String toString() {
+            return "{uid=" + uid + " frameRateHz=" + frameRateHz + "}";
+        }
+    }
+
+    /**
+     * Called when frame rate override event is received.
+     *
+     * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
+     * timebase.
+     * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
+     * @param overrides The mappings from uid to frame rates
+     */
+    public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+            FrameRateOverride[] overrides) {
+    }
+
+    /**
      * Schedules a single vertical sync pulse to be delivered when the next
      * display frame begins.
      */
@@ -240,4 +277,11 @@
         onConfigChanged(timestampNanos, physicalDisplayId, configId);
     }
 
+    // Called from native code.
+    @SuppressWarnings("unused")
+    private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId,
+            FrameRateOverride[] overrides) {
+        onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
+    }
+
 }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index fe9a1a7..0201605 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -261,6 +261,11 @@
     public String ownerPackageName;
 
     /**
+     * The refresh rate override for this app. 0 means no override.
+     */
+    public float refreshRateOverride;
+
+    /**
      * @hide
      * Get current remove mode of the display - what actions should be performed with the display's
      * content when it is removed.
@@ -332,7 +337,8 @@
                 && state == other.state
                 && ownerUid == other.ownerUid
                 && Objects.equals(ownerPackageName, other.ownerPackageName)
-                && removeMode == other.removeMode;
+                && removeMode == other.removeMode
+                && refreshRateOverride == other.refreshRateOverride;
     }
 
     @Override
@@ -376,6 +382,7 @@
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
         removeMode = other.removeMode;
+        refreshRateOverride = other.refreshRateOverride;
     }
 
     public void readFromParcel(Parcel source) {
@@ -421,6 +428,7 @@
         ownerPackageName = source.readString8();
         uniqueId = source.readString8();
         removeMode = source.readInt();
+        refreshRateOverride = source.readFloat();
     }
 
     @Override
@@ -465,6 +473,7 @@
         dest.writeString8(ownerPackageName);
         dest.writeString8(uniqueId);
         dest.writeInt(removeMode);
+        dest.writeFloat(refreshRateOverride);
     }
 
     @Override
@@ -472,6 +481,17 @@
         return 0;
     }
 
+    /**
+     * Returns the refresh rate the application would experience.
+     */
+    public float getRefreshRate() {
+        if (refreshRateOverride > 0) {
+            return refreshRateOverride;
+        }
+
+        return getMode().getRefreshRate();
+    }
+
     public Display.Mode getMode() {
         return findMode(modeId);
     }
@@ -675,6 +695,9 @@
         }
         sb.append(", removeMode ");
         sb.append(removeMode);
+        sb.append(", refreshRateOverride ");
+        sb.append(refreshRateOverride);
+
         sb.append("}");
         return sb.toString();
     }
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index defa58e..c8bfd36 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -15,8 +15,13 @@
  */
 
 package android.view;
+
+import android.annotation.IntDef;
 import android.graphics.Rect;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Standard constants and tools for placing an object within a potentially
  * larger container.
@@ -122,6 +127,32 @@
      */
     public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
 
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
+        Gravity.FILL,
+        Gravity.FILL_HORIZONTAL,
+        Gravity.FILL_VERTICAL,
+        Gravity.START,
+        Gravity.END,
+        Gravity.LEFT,
+        Gravity.RIGHT,
+        Gravity.TOP,
+        Gravity.BOTTOM,
+        Gravity.CENTER,
+        Gravity.CENTER_HORIZONTAL,
+        Gravity.CENTER_VERTICAL,
+        Gravity.DISPLAY_CLIP_HORIZONTAL,
+        Gravity.DISPLAY_CLIP_VERTICAL,
+        Gravity.CLIP_HORIZONTAL,
+        Gravity.CLIP_VERTICAL,
+        Gravity.NO_GRAVITY
+    })
+    public @interface GravityFlags {}
+
     /**
      * Apply a gravity constant to an object. This supposes that the layout direction is LTR.
      * 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0533533..a23b7e1 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -32,6 +32,7 @@
 import android.os.Bundle;
 import android.os.IRemoteCallback;
 import android.os.ParcelFileDescriptor;
+import android.service.attestation.ImpressionToken;
 import android.view.DisplayCutout;
 import android.view.IApplicationToken;
 import android.view.IAppTransitionAnimationSpecsFuture;
@@ -648,24 +649,24 @@
     void setShouldShowSystemDecors(int displayId, boolean shouldShow);
 
     /**
-     * Indicates that the display should show IME.
+     * Indicates the policy for how the display should show IME.
      *
      * @param displayId The id of the display.
-     * @return {@code true} if the display should show IME.
+     * @return The policy for how the display should show IME.
      * @see KeyguardManager#isDeviceSecure()
      * @see KeyguardManager#isDeviceLocked()
      */
-    boolean shouldShowIme(int displayId);
+    int getDisplayImePolicy(int displayId);
 
     /**
-     * Sets that the display should show IME.
+     * Sets the policy for how the display should show IME.
      *
      * @param displayId The id of the display.
-     * @param shouldShow Indicates that the display should show IME.
+     * @param imePolicy Indicates the policy for how the display should show IME.
      * @see KeyguardManager#isDeviceSecure()
      * @see KeyguardManager#isDeviceLocked()
      */
-    void setShouldShowIme(int displayId, boolean shouldShow);
+    void setDisplayImePolicy(int displayId, int imePolicy);
 
     /**
      * Waits for transactions to get applied before injecting input, optionally waiting for
@@ -760,4 +761,23 @@
      * {@link android.content.pm.PackageManager#getHoldLockToken()}.
      */
     void holdLock(in IBinder token, in int durationMs);
+
+    /**
+     * Gets an array of support hashing algorithms that can be used to generate the hash of the
+     * screenshot. The String value of one algorithm should be used when requesting to generate
+     * the impression attestation token.
+     *
+     * @return a String array of supported hashing algorithms.
+     */
+    String[] getSupportedImpressionAlgorithms();
+
+    /**
+     * Validate the impression token was generated by the system. The impression token passed in
+     * should be the token generated when calling {@link IWindowSession#generateImpressionToken}
+     *
+     * @param impressionToken The token to verify that it was generated by the system.
+     * @return true if the token was generated by the system or false if the token cannot be
+     *         verified.
+     */
+    boolean verifyImpressionToken(in ImpressionToken impressionToken);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 0089a85..cfdaf8c 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -22,6 +22,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
+import android.service.attestation.ImpressionToken;
 import android.util.MergedConfiguration;
 import android.view.DisplayCutout;
 import android.view.InputChannel;
@@ -344,4 +345,16 @@
      *                     window, the system will try to find a new focus target.
      */
     void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus);
+
+    /**
+     * Generates an impression token that can be used to validate whether specific content was on
+     * screen.
+     *
+     * @param window The token for the window where the view to attest is shown.
+     * @param boundsInWindow The size and position of the ads view in the window
+     * @param hashAlgorithm The String for the hashing algorithm to use based on values returned
+     *                      from {@link IWindowManager#getSupportedImpressionAlgorithms()}
+     */
+    ImpressionToken generateImpressionToken(IWindow window, in Rect boundsInWindow,
+            in String hashAlgorithm);
 }
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index efc0bd2..4a5c95f 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -222,6 +222,25 @@
     }
 
     /**
+     * To handle the lifecycle of the input connection when the device interactivity state changed.
+     * (i.e. Calling IMS#onFinishInput when the device screen-off and Calling IMS#onStartInput
+     * when the device screen-on again).
+     */
+    @UiThread
+    public void onInteractiveChanged(boolean interactive) {
+        final InputMethodManagerDelegate immDelegate = getImmDelegate();
+        if (!immDelegate.isCurrentRootView(mViewRootImpl)) {
+            return;
+        }
+        if (interactive) {
+            final View focusedView = mViewRootImpl.mView.findFocus();
+            onViewFocusChanged(focusedView, focusedView != null);
+        } else {
+            mDelegate.finishInputAndReportToIme();
+        }
+    }
+
+    /**
      * @param windowAttribute {@link WindowManager.LayoutParams} to be checked.
      * @return Whether the window is in local focus mode or not.
      */
@@ -256,6 +275,7 @@
                 @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags,
                 boolean forceNewFocus);
         void finishInput();
+        void finishInputAndReportToIme();
         void closeCurrentIme();
         void finishComposingText();
         void setCurrentRootView(ViewRootImpl rootView);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 22ac4dc..8da833a 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -29,6 +29,8 @@
 import android.os.Parcelable;
 import android.os.Vibrator;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -423,9 +425,13 @@
         }
     };
 
-    // Called by native code.
+    /**
+     * Called by native code
+     * @hide
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
+    @VisibleForTesting
+    public InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
             int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
             KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMicrophone,
             boolean hasButtonUnderPad) {
diff --git a/core/java/android/view/OnReceiveContentListener.java b/core/java/android/view/OnReceiveContentListener.java
index db9c538..b551fa8 100644
--- a/core/java/android/view/OnReceiveContentListener.java
+++ b/core/java/android/view/OnReceiveContentListener.java
@@ -16,22 +16,8 @@
 
 package android.view;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ClipData;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.ArrayMap;
-
-import com.android.internal.util.Preconditions;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.Objects;
-import java.util.function.Predicate;
 
 /**
  * Listener for apps to implement handling for insertion of content. Content may be both text and
@@ -48,10 +34,13 @@
  *     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
  *
  *     &#64;Override
- *     public Payload onReceiveContent(View view, Payload payload) {
- *         Map&lt;Boolean, Payload&gt; split = payload.partition(item -&gt; item.getUri() != null);
- *         if (split.get(true) != null) {
- *             ClipData clip = payload.getClip();
+ *     public ContentInfo onReceiveContent(View view, ContentInfo payload) {
+ *         Map&lt;Boolean, ContentInfo&gt; split =
+ *                 payload.partition(item -&gt; item.getUri() != null);
+ *         ContentInfo uriItems = split.get(true);
+ *         ContentInfo remainingItems = split.get(false);
+ *         if (uriItems != null) {
+ *             ClipData clip = uriItems.getClip();
  *             for (int i = 0; i < clip.getItemCount(); i++) {
  *                 Uri uri = clip.getItemAt(i).getUri();
  *                 // ... app-specific logic to handle the URI ...
@@ -59,7 +48,7 @@
  *         }
  *         // Return anything that we didn't handle ourselves. This preserves the default platform
  *         // behavior for text and anything else for which we are not implementing custom handling.
- *         return split.get(false);
+ *         return remainingItems;
  *     }
  * }
  *
@@ -83,8 +72,8 @@
      * handling. For example, an implementation may provide handling for content URIs (to provide
      * support for inserting images, etc) and delegate the processing of text to the platform to
      * preserve the common behavior for inserting text. See the class javadoc for a sample
-     * implementation and see {@link Payload#partition} for a convenient way to split the passed-in
-     * content.
+     * implementation and see {@link ContentInfo#partition} for a convenient way to split the
+     * passed-in content.
      *
      * <p>If implementing handling for text: if the view has a selection, the selection should
      * be overwritten by the passed-in content; if there's no selection, the passed-in content
@@ -103,314 +92,6 @@
      * succeed even if this method returns null. For example, an app may end up not inserting
      * an item if it exceeds the app's size limit for that type of content.
      */
-    @Nullable Payload onReceiveContent(@NonNull View view, @NonNull Payload payload);
-
-    /**
-     * Holds all the relevant data for a request to {@link OnReceiveContentListener}.
-     */
-    final class Payload {
-
-        /**
-         * Specifies the UI through which content is being inserted. Future versions of Android may
-         * support additional values.
-         *
-         * @hide
-         */
-        @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
-                SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Source {}
-
-        /**
-         * Specifies that the operation was triggered by the app that contains the target view.
-         */
-        public static final int SOURCE_APP = 0;
-
-        /**
-         * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
-         * "Paste as plain text" action in the insertion/selection menu).
-         */
-        public static final int SOURCE_CLIPBOARD = 1;
-
-        /**
-         * Specifies that the operation was triggered from the soft keyboard (also known as input
-         * method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
-         * for more info.
-         */
-        public static final int SOURCE_INPUT_METHOD = 2;
-
-        /**
-         * Specifies that the operation was triggered by the drag/drop framework. See
-         * https://developer.android.com/guide/topics/ui/drag-drop for more info.
-         */
-        public static final int SOURCE_DRAG_AND_DROP = 3;
-
-        /**
-         * Specifies that the operation was triggered by the autofill framework. See
-         * https://developer.android.com/guide/topics/text/autofill for more info.
-         */
-        public static final int SOURCE_AUTOFILL = 4;
-
-        /**
-         * Specifies that the operation was triggered by a result from a
-         * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
-         * menu.
-         */
-        public static final int SOURCE_PROCESS_TEXT = 5;
-
-        /**
-         * Returns the symbolic name of the given source.
-         *
-         * @hide
-         */
-        static String sourceToString(@Source int source) {
-            switch (source) {
-                case SOURCE_APP: return "SOURCE_APP";
-                case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
-                case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
-                case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
-                case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
-                case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
-            }
-            return String.valueOf(source);
-        }
-
-        /**
-         * Flags to configure the insertion behavior.
-         *
-         * @hide
-         */
-        @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Flags {}
-
-        /**
-         * Flag requesting that the content should be converted to plain text prior to inserting.
-         */
-        public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
-
-        /**
-         * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
-         *
-         * @hide
-         */
-        static String flagsToString(@Flags int flags) {
-            if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
-                return "FLAG_CONVERT_TO_PLAIN_TEXT";
-            }
-            return String.valueOf(flags);
-        }
-
-        @NonNull private final ClipData mClip;
-        private final @Source int mSource;
-        private final @Flags int mFlags;
-        @Nullable private final Uri mLinkUri;
-        @Nullable private final Bundle mExtras;
-
-        private Payload(Builder b) {
-            this.mClip = Objects.requireNonNull(b.mClip);
-            this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
-                    "source");
-            this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
-            this.mLinkUri = b.mLinkUri;
-            this.mExtras = b.mExtras;
-        }
-
-        @NonNull
-        @Override
-        public String toString() {
-            return "Payload{"
-                    + "clip=" + mClip
-                    + ", source=" + sourceToString(mSource)
-                    + ", flags=" + flagsToString(mFlags)
-                    + ", linkUri=" + mLinkUri
-                    + ", extras=" + mExtras
-                    + "}";
-        }
-
-        /**
-         * The data to be inserted.
-         */
-        public @NonNull ClipData getClip() {
-            return mClip;
-        }
-
-        /**
-         * The source of the operation. See {@code SOURCE_} constants. Future versions of Android
-         * may pass additional values.
-         */
-        public @Source int getSource() {
-            return mSource;
-        }
-
-        /**
-         * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
-         */
-        public @Flags int getFlags() {
-            return mFlags;
-        }
-
-        /**
-         * Optional http/https URI for the content that may be provided by the IME. This is only
-         * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
-         * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
-         * IME.
-         */
-        public @Nullable Uri getLinkUri() {
-            return mLinkUri;
-        }
-
-        /**
-         * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
-         * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
-         * the IME.
-         */
-        public @Nullable Bundle getExtras() {
-            return mExtras;
-        }
-
-        /**
-         * Partitions this payload based on the given predicate.
-         *
-         * <p>Similar to a
-         * {@link java.util.stream.Collectors#partitioningBy(Predicate) partitioning collector},
-         * this function classifies the content in this payload and organizes it into a map,
-         * grouping the content that matched vs didn't match the predicate.
-         *
-         * <p>Except for the {@link ClipData} items, the returned payloads will contain all the same
-         * metadata as the original payload.
-         *
-         * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which
-         * partition to place it into.
-         * @return A map containing the partitioned content. The map will contain a single entry if
-         * all items were classified into the same partition (all matched or all didn't match the
-         * predicate) or two entries (if there's at least one item that matched the predicate and at
-         * least one item that didn't match the predicate).
-         */
-        public @NonNull Map<Boolean, Payload> partition(
-                @NonNull Predicate<ClipData.Item> itemPredicate) {
-            if (mClip.getItemCount() == 1) {
-                Map<Boolean, Payload> result = new ArrayMap<>(1);
-                result.put(itemPredicate.test(mClip.getItemAt(0)), this);
-                return result;
-            }
-            ArrayList<ClipData.Item> accepted = new ArrayList<>();
-            ArrayList<ClipData.Item> remaining = new ArrayList<>();
-            for (int i = 0; i < mClip.getItemCount(); i++) {
-                ClipData.Item item = mClip.getItemAt(i);
-                if (itemPredicate.test(item)) {
-                    accepted.add(item);
-                } else {
-                    remaining.add(item);
-                }
-            }
-            Map<Boolean, Payload> result = new ArrayMap<>(2);
-            if (!accepted.isEmpty()) {
-                ClipData acceptedClip = new ClipData(mClip.getDescription(), accepted);
-                result.put(true, new Builder(this).setClip(acceptedClip).build());
-            }
-            if (!remaining.isEmpty()) {
-                ClipData remainingClip = new ClipData(mClip.getDescription(), remaining);
-                result.put(false, new Builder(this).setClip(remainingClip).build());
-            }
-            return result;
-        }
-
-        /**
-         * Builder for {@link Payload}.
-         */
-        public static final class Builder {
-            @NonNull private ClipData mClip;
-            private @Source int mSource;
-            private @Flags int mFlags;
-            @Nullable private Uri mLinkUri;
-            @Nullable private Bundle mExtras;
-
-            /**
-             * Creates a new builder initialized with the data from the given builder.
-             */
-            public Builder(@NonNull Payload payload) {
-                mClip = payload.mClip;
-                mSource = payload.mSource;
-                mFlags = payload.mFlags;
-                mLinkUri = payload.mLinkUri;
-                mExtras = payload.mExtras;
-            }
-
-            /**
-             * Creates a new builder.
-             * @param clip   The data to insert.
-             * @param source The source of the operation. See {@code SOURCE_} constants.
-             */
-            public Builder(@NonNull ClipData clip, @Source int source) {
-                mClip = clip;
-                mSource = source;
-            }
-
-            /**
-             * Sets the data to be inserted.
-             * @param clip The data to insert.
-             * @return this builder
-             */
-            @NonNull
-            public Builder setClip(@NonNull ClipData clip) {
-                mClip = clip;
-                return this;
-            }
-
-            /**
-             * Sets the source of the operation.
-             * @param source The source of the operation. See {@code SOURCE_} constants.
-             * @return this builder
-             */
-            @NonNull
-            public Builder setSource(@Source int source) {
-                mSource = source;
-                return this;
-            }
-
-            /**
-             * Sets flags that control content insertion behavior.
-             * @param flags Optional flags to configure the insertion behavior. Use 0 for default
-             *              behavior. See {@code FLAG_} constants.
-             * @return this builder
-             */
-            @NonNull
-            public Builder setFlags(@Flags int flags) {
-                mFlags = flags;
-                return this;
-            }
-
-            /**
-             * Sets the http/https URI for the content. See
-             * {@link android.view.inputmethod.InputContentInfo#getLinkUri} for more info.
-             * @param linkUri Optional http/https URI for the content.
-             * @return this builder
-             */
-            @NonNull
-            public Builder setLinkUri(@Nullable Uri linkUri) {
-                mLinkUri = linkUri;
-                return this;
-            }
-
-            /**
-             * Sets additional metadata.
-             * @param extras Optional bundle with additional metadata.
-             * @return this builder
-             */
-            @NonNull
-            public Builder setExtras(@Nullable Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /**
-             * @return A new {@link Payload} instance with the data from this builder.
-             */
-            @NonNull
-            public Payload build() {
-                return new Payload(this);
-            }
-        }
-    }
+    @Nullable
+    ContentInfo onReceiveContent(@NonNull View view, @NonNull ContentInfo payload);
 }
diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING
index 4ea4310..c8b746f 100644
--- a/core/java/android/view/TEST_MAPPING
+++ b/core/java/android/view/TEST_MAPPING
@@ -2,6 +2,24 @@
   "presubmit": [
     {
       "name": "CtsAccelerationTestCases"
+    },
+    {
+      "name": "CtsOsTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.os.cts.StrictModeTest"
+        }
+      ],
+      "file_patterns": ["(/|^)ViewConfiguration.java", "(/|^)GestureDetector.java"]
     }
   ],
   "imports": [
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 30ec2b0..a5c6653 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -112,7 +112,6 @@
 import android.view.AccessibilityIterators.WordTextSegmentIterator;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.InputDevice.InputSourceClass;
-import android.view.OnReceiveContentListener.Payload;
 import android.view.Window.OnContentApplyWindowInsetsListener;
 import android.view.WindowInsets.Type;
 import android.view.WindowInsetsAnimation.Bounds;
@@ -9063,11 +9062,12 @@
      * @return The portion of the passed-in content that was not accepted (may be all, some, or none
      * of the passed-in content).
      */
-    public @Nullable Payload performReceiveContent(@NonNull Payload payload) {
+    @Nullable
+    public ContentInfo performReceiveContent(@NonNull ContentInfo payload) {
         final OnReceiveContentListener listener = (mListenerInfo == null) ? null
                 : getListenerInfo().mOnReceiveContentListener;
         if (listener != null) {
-            final Payload remaining = listener.onReceiveContent(this, payload);
+            final ContentInfo remaining = listener.onReceiveContent(this, payload);
             return (remaining == null) ? null : onReceiveContent(remaining);
         }
         return onReceiveContent(payload);
@@ -9088,7 +9088,8 @@
      * @return The portion of the passed-in content that was not handled (may be all, some, or none
      * of the passed-in content).
      */
-    public @Nullable Payload onReceiveContent(@NonNull Payload payload) {
+    @Nullable
+    public ContentInfo onReceiveContent(@NonNull ContentInfo payload) {
         return payload;
     }
 
@@ -9113,7 +9114,8 @@
      * @return The MIME types accepted by {@link #performReceiveContent} for this view (may
      * include patterns such as "image/*").
      */
-    public @Nullable String[] getOnReceiveContentMimeTypes() {
+    @Nullable
+    public String[] getOnReceiveContentMimeTypes() {
         return mOnReceiveContentMimeTypes;
     }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 436acef..b9afbc9 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -104,6 +104,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
+import android.view.Gravity.GravityFlags;
 import android.view.View.OnApplyWindowInsetsListener;
 import android.view.WindowInsets.Side;
 import android.view.WindowInsets.Side.InsetsSide;
@@ -461,6 +462,40 @@
     @interface RemoveContentMode {}
 
     /**
+     * Display IME Policy: The IME should appear on the local display.
+     * @hide
+     */
+    @TestApi
+    int DISPLAY_IME_POLICY_LOCAL = 0;
+
+    /**
+     * Display IME Policy: The IME should appear on the fallback display.
+     * @hide
+     */
+    @TestApi
+    int DISPLAY_IME_POLICY_FALLBACK_DISPLAY = 1;
+
+    /**
+     * Display IME Policy: The IME should be hidden.
+     *
+     * Setting this policy will prevent the IME from making a connection. This
+     * will prevent any IME from receiving metadata about input.
+     * @hide
+     */
+    @TestApi
+    int DISPLAY_IME_POLICY_HIDE = 2;
+
+    /**
+     * @hide
+     */
+    @IntDef({
+            DISPLAY_IME_POLICY_LOCAL,
+            DISPLAY_IME_POLICY_FALLBACK_DISPLAY,
+            DISPLAY_IME_POLICY_HIDE,
+    })
+    @interface DisplayImePolicy {}
+
+    /**
      * Exception that is thrown when trying to add view whose
      * {@link LayoutParams} {@link LayoutParams#token}
      * is invalid.
@@ -695,27 +730,26 @@
     }
 
     /**
-     * Sets that the display should show IME.
+     * Sets the policy for how the display should show IME.
      *
      * @param displayId Display ID.
-     * @param shouldShow Indicates that the display should show IME.
+     * @param imePolicy Indicates the policy for how the display should show IME.
      * @hide
      */
     @TestApi
-    default void setShouldShowIme(int displayId, boolean shouldShow) {
+    default void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) {
     }
 
     /**
-     * Indicates that the display should show IME.
+     * Indicates the policy for how the display should show IME.
      *
      * @param displayId The id of the display.
-     * @return {@code true} if the display should show IME when an input field becomes
-     * focused on it.
+     * @return The policy for how the display should show IME.
      * @hide
      */
     @TestApi
-    default boolean shouldShowIme(int displayId) {
-        return false;
+    default @DisplayImePolicy int getDisplayImePolicy(int displayId) {
+        return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
     }
 
     public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
@@ -2124,15 +2158,6 @@
         public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000;
 
         /**
-         * Flag to indicate that this window should be considered a screen decoration similar to the
-         * nav bar and status bar. This will cause this window to affect the window insets reported
-         * to other windows when it is visible.
-         * @hide
-         */
-        @RequiresPermission(permission.STATUS_BAR_SERVICE)
-        public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000;
-
-        /**
          * Flag to indicate that the status bar window is in a state such that it forces showing
          * the navigation bar unless the navigation bar window is explicitly set to
          * {@link View#GONE}.
@@ -2237,7 +2262,6 @@
                 PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
                 SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
                 PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
-                PRIVATE_FLAG_IS_SCREEN_DECOR,
                 PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
                 PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
                 PRIVATE_FLAG_USE_BLAST,
@@ -2325,10 +2349,6 @@
                         equals = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
                         name = "IS_ROUNDED_CORNERS_OVERLAY"),
                 @ViewDebug.FlagToString(
-                        mask = PRIVATE_FLAG_IS_SCREEN_DECOR,
-                        equals = PRIVATE_FLAG_IS_SCREEN_DECOR,
-                        name = "IS_SCREEN_DECOR"),
-                @ViewDebug.FlagToString(
                         mask = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
                         equals = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
                         name = "STATUS_FORCE_SHOW_NAVIGATION"),
@@ -2553,6 +2573,7 @@
          *
          * @see Gravity
          */
+        @GravityFlags
         public int gravity;
 
         /**
@@ -2826,7 +2847,6 @@
         /** @hide */
         @Retention(RetentionPolicy.SOURCE)
         @IntDef(
-                flag = true,
                 value = {LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
                         LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,
                         LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER,
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index d56929e..3384bbe 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -201,20 +201,20 @@
     }
 
     @Override
-    public void setShouldShowIme(int displayId, boolean shouldShow) {
+    public void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) {
         try {
-            WindowManagerGlobal.getWindowManagerService().setShouldShowIme(displayId, shouldShow);
+            WindowManagerGlobal.getWindowManagerService().setDisplayImePolicy(displayId, imePolicy);
         } catch (RemoteException e) {
         }
     }
 
     @Override
-    public boolean shouldShowIme(int displayId) {
+    public @DisplayImePolicy int getDisplayImePolicy(int displayId) {
         try {
-            return WindowManagerGlobal.getWindowManagerService().shouldShowIme(displayId);
+            return WindowManagerGlobal.getWindowManagerService().getDisplayImePolicy(displayId);
         } catch (RemoteException e) {
         }
-        return false;
+        return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
     }
 
     @Override
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 0ed7ca7..673073e 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -24,6 +24,7 @@
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.service.attestation.ImpressionToken;
 import android.util.Log;
 import android.util.MergedConfiguration;
 import android.window.ClientWindowFrames;
@@ -460,4 +461,10 @@
     public void grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken,
                                          boolean grantFocus) {
     }
+
+    @Override
+    public ImpressionToken generateImpressionToken(IWindow window, Rect boundsInWindow,
+            String hashAlgorithm) {
+        return null;
+    }
 }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 8fdcac7..364ae818 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -19,7 +19,7 @@
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
 import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
 import static android.view.autofill.Helper.sDebug;
 import static android.view.autofill.Helper.sVerbose;
 import static android.view.autofill.Helper.toList;
@@ -61,8 +61,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Choreographer;
+import android.view.ContentInfo;
 import android.view.KeyEvent;
-import android.view.OnReceiveContentListener.Payload;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -2371,8 +2371,8 @@
                 reportAutofillContentFailure(id);
                 return;
             }
-            Payload payload = new Payload.Builder(clip, SOURCE_AUTOFILL).build();
-            Payload result = view.performReceiveContent(payload);
+            ContentInfo payload = new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
+            ContentInfo result = view.performReceiveContent(payload);
             if (result != null) {
                 Log.w(TAG, "autofillContent(): receiver could not insert content: id=" + id
                         + ", view=" + view + ", clip=" + clip);
diff --git a/core/java/android/view/autofill/TEST_MAPPING b/core/java/android/view/autofill/TEST_MAPPING
new file mode 100644
index 0000000..87a17eb
--- /dev/null
+++ b/core/java/android/view/autofill/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+    {
+      "path": "frameworks/base/services/autofill/java/com/android/server/autofill"
+    }
+  ]
+}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 1ab9edf..f057c12 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,7 +16,7 @@
 
 package android.view.inputmethod;
 
-import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
+import static android.view.ContentInfo.SOURCE_INPUT_METHOD;
 
 import android.annotation.CallSuper;
 import android.annotation.IntRange;
@@ -38,9 +38,9 @@
 import android.text.method.MetaKeyKeyListener;
 import android.util.Log;
 import android.util.LogPrinter;
+import android.view.ContentInfo;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
-import android.view.OnReceiveContentListener;
 import android.view.View;
 
 import com.android.internal.util.Preconditions;
@@ -952,8 +952,8 @@
         }
         final ClipData clip = new ClipData(inputContentInfo.getDescription(),
                 new ClipData.Item(inputContentInfo.getContentUri()));
-        final OnReceiveContentListener.Payload payload =
-                new OnReceiveContentListener.Payload.Builder(clip, SOURCE_INPUT_METHOD)
+        final ContentInfo payload =
+                new ContentInfo.Builder(clip, SOURCE_INPUT_METHOD)
                 .setLinkUri(inputContentInfo.getLinkUri())
                 .setExtras(opts)
                 .build();
diff --git a/core/java/android/view/inputmethod/DumpableInputConnection.java b/core/java/android/view/inputmethod/DumpableInputConnection.java
new file mode 100644
index 0000000..9819a57
--- /dev/null
+++ b/core/java/android/view/inputmethod/DumpableInputConnection.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.util.proto.ProtoOutputStream;
+
+/** @hide */
+public interface DumpableInputConnection {
+
+    /**
+     * Method used to dump state of InputConnection implementations of interest.
+     *
+     * @param proto Stream to write the state to
+     * @param fieldId FieldId of DumpableInputConnection as defined in the parent message
+     */
+    void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId);
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3c89a4b..8d2c2d9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -22,6 +22,7 @@
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_METHOD_MANAGER;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.VIEW_ROOT_IMPL;
 import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
@@ -87,8 +88,10 @@
 import android.view.autofill.AutofillManager;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.Completable;
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.inputmethod.ResultCallbacks;
 import com.android.internal.inputmethod.StartInputFlags;
 import com.android.internal.inputmethod.StartInputReason;
 import com.android.internal.inputmethod.UnbindReason;
@@ -599,6 +602,27 @@
         }
 
         /**
+         * Used by {@link ImeFocusController} to finish input connection and callback
+         * {@link InputMethodService#onFinishInput()}.
+         *
+         * This method is especially for when ImeFocusController received device screen-off event to
+         * ensure the entire finish input connection and the connection lifecycle callback to
+         * IME can be done for security concern.
+         */
+        @Override
+        public void finishInputAndReportToIme() {
+            synchronized (mH) {
+                finishInputLocked();
+                if (mCurMethod != null) {
+                    try {
+                        mCurMethod.finishInput();
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+
+        /**
          * Used by {@link ImeFocusController} to hide current input method editor.
          */
         @Override
@@ -644,6 +668,7 @@
                     final int startInputReason =
                             nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
                                     : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
+                    final Completable.InputBindResult value = Completable.createInputBindResult();
                     mService.startInputOrWindowGainedFocus(
                             startInputReason, mClient,
                             focusedView.getWindowToken(), startInputFlags, softInputMode,
@@ -651,7 +676,9 @@
                             null,
                             null,
                             0 /* missingMethodFlags */,
-                            mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
+                            mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
+                            ResultCallbacks.of(value));
+                    Completable.getResult(value); // ignore the result
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -849,12 +876,23 @@
                 case MSG_SET_ACTIVE: {
                     final boolean active = msg.arg1 != 0;
                     final boolean fullscreen = msg.arg2 != 0;
+                    final boolean reportToImeController = msg.obj != null && (boolean) msg.obj;
                     if (DEBUG) {
                         Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
                     }
                     synchronized (mH) {
                         mActive = active;
                         mFullscreenMode = fullscreen;
+
+                        // Report active state to ImeFocusController to handle IME input
+                        // connection lifecycle callback when it allowed.
+                        final ImeFocusController controller = getFocusController();
+                        final View rootView = mCurRootView != null ? mCurRootView.getView() : null;
+                        if (controller != null && rootView != null && reportToImeController) {
+                            rootView.post(() -> controller.onInteractiveChanged(active));
+                            return;
+                        }
+
                         if (!active) {
                             // Some other client has starting using the IME, so note
                             // that this happened and make sure our own editor's
@@ -966,9 +1004,9 @@
         private final InputMethodManager mParentInputMethodManager;
         private final WeakReference<View> mServedView;
 
-        ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn,
+        ControlledInputConnectionWrapper(Looper icLooper, InputConnection conn,
                 InputMethodManager inputMethodManager, View servedView) {
-            super(mainLooper, conn);
+            super(icLooper, conn);
             mParentInputMethodManager = inputMethodManager;
             mServedView = new WeakReference<>(servedView);
         }
@@ -1014,6 +1052,18 @@
                     + " mServedView=" + mServedView.get()
                     + "}";
         }
+
+        void dumpDebug(ProtoOutputStream proto, long fieldId) {
+            // Check that the call is initiated in the main thread of the current InputConnection
+            // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
+            // executed on this thread. Otherwise the messages are dispatched to the correct thread
+            // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
+            // reasons.
+            if (getInputConnection() instanceof DumpableInputConnection && Looper.myLooper()
+                    == getLooper()) {
+                ((DumpableInputConnection) getInputConnection()).dumpDebug(proto, fieldId);
+            }
+        }
     }
 
     private static class ImeThreadFactory implements ThreadFactory {
@@ -1061,8 +1111,9 @@
         }
 
         @Override
-        public void setActive(boolean active, boolean fullscreen) {
-            mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget();
+        public void setActive(boolean active, boolean fullscreen, boolean reportToImeController) {
+            mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0,
+                    reportToImeController).sendToTarget();
         }
 
         @Override
@@ -1993,10 +2044,13 @@
                 if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
                         + ic + " tba=" + tba + " startInputFlags="
                         + InputMethodDebug.startInputFlagsToString(startInputFlags));
-                res = mService.startInputOrWindowGainedFocus(
+                final Completable.InputBindResult value = Completable.createInputBindResult();
+                mService.startInputOrWindowGainedFocus(
                         startInputReason, mClient, windowGainingFocus, startInputFlags,
                         softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
-                        view.getContext().getApplicationInfo().targetSdkVersion);
+                        view.getContext().getApplicationInfo().targetSdkVersion,
+                        ResultCallbacks.of(value));
+                res = Completable.getResult(value);
                 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
                 if (res == null) {
                     Log.wtf(TAG, "startInputOrWindowGainedFocus must not return"
@@ -2174,6 +2228,7 @@
      * @hide
      */
     public void notifyImeHidden(IBinder windowToken) {
+        ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this);
         synchronized (mH) {
             try {
                 if (mCurMethod != null && mCurRootView != null
@@ -3279,6 +3334,9 @@
             if (mImeInsetsConsumer != null) {
                 mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER);
             }
+            if (mServedInputConnectionWrapper != null) {
+                mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION);
+            }
         }
     }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 14abbdb..9c63d56 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -71,7 +71,8 @@
     // TODO: remove this
     private static final String EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME =
             "UntranslatableReplacementStringInSubtypeName";
-    private static final int SUBTYPE_ID_NONE = 0;
+    /** {@hide} */
+    public static final int SUBTYPE_ID_NONE = 0;
 
     private final boolean mIsAuxiliary;
     private final boolean mOverridesImplicitlyEnabledSubtype;
diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java
index d7b4e8b..21fa6fc8 100644
--- a/core/java/android/webkit/PacProcessor.java
+++ b/core/java/android/webkit/PacProcessor.java
@@ -54,7 +54,7 @@
      */
     @NonNull
     static PacProcessor createInstance() {
-        throw new UnsupportedOperationException("Not implemented");
+        return WebViewFactory.getProvider().createPacProcessor();
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index dde9c30..b91e7d3 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -251,15 +251,8 @@
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
             try {
                 Class<WebViewFactoryProvider> providerClass = getProviderClass();
-                Method staticFactory = null;
-                try {
-                    staticFactory = providerClass.getMethod(
+                Method staticFactory = providerClass.getMethod(
                         CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);
-                } catch (Exception e) {
-                    if (DEBUG) {
-                        Log.w(LOGTAG, "error instantiating provider with static factory method", e);
-                    }
-                }
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");
                 try {
@@ -267,12 +260,12 @@
                             staticFactory.invoke(null, new WebViewDelegate());
                     if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
                     return sProviderInstance;
-                } catch (Exception e) {
-                    Log.e(LOGTAG, "error instantiating provider", e);
-                    throw new AndroidRuntimeException(e);
                 } finally {
                     Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
                 }
+            } catch (Exception e) {
+                Log.e(LOGTAG, "error instantiating provider", e);
+                throw new AndroidRuntimeException(e);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
             }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 00ba326..0025d1e 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
+import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
 
 import android.R;
 import android.animation.ValueAnimator;
@@ -87,6 +87,7 @@
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.ActionMode.Callback;
+import android.view.ContentInfo;
 import android.view.ContextMenu;
 import android.view.ContextThemeWrapper;
 import android.view.DragAndDropPermissions;
@@ -98,7 +99,6 @@
 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;
@@ -2869,8 +2869,8 @@
             final int originalLength = mTextView.getText().length();
             Selection.setSelection((Spannable) mTextView.getText(), offset);
             final ClipData clip = event.getClipData();
-            final OnReceiveContentListener.Payload payload =
-                    new OnReceiveContentListener.Payload.Builder(clip, SOURCE_DRAG_AND_DROP)
+            final ContentInfo payload =
+                    new ContentInfo.Builder(clip, SOURCE_DRAG_AND_DROP)
                     .build();
             mTextView.performReceiveContent(payload);
             if (dragDropIntoItself) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 7c20472..4f1c40a 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -2773,6 +2773,7 @@
                 int left, int top, int right, int bottom) {
             AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo();
             info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
+            info.setAccessibilityFocused(mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT);
             if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) {
                 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
             }
@@ -2802,6 +2803,7 @@
             info.setClickable(true);
             info.setLongClickable(true);
             info.setEnabled(NumberPicker.this.isEnabled());
+            info.setAccessibilityFocused(mAccessibilityFocusedView == virtualViewId);
             Rect boundsInParent = mTempRect;
             boundsInParent.set(left, top, right, bottom);
             info.setVisibleToUser(isVisibleToUser(boundsInParent));
@@ -2843,6 +2845,7 @@
             info.setParent((View) getParentForAccessibility());
             info.setEnabled(NumberPicker.this.isEnabled());
             info.setScrollable(true);
+            info.setAccessibilityFocused(mAccessibilityFocusedView == View.NO_ID);
 
             final float applicationScale =
                 getContext().getResources().getCompatibilityInfo().applicationScale;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index e74ce53..e08ccfd 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -1022,7 +1022,13 @@
         protected SelectionResult doInBackground(Void... params) {
             final Runnable onTimeOut = this::onTimeOut;
             mTextView.postDelayed(onTimeOut, mTimeOutDuration);
-            final SelectionResult result = mSelectionResultSupplier.get();
+            SelectionResult result = null;
+            try {
+                result = mSelectionResultSupplier.get();
+            } catch (IllegalStateException e) {
+                // TODO(b/174300371): Only swallows the exception if the TCSession is destroyed
+                Log.w(LOG_TAG, "TextClassificationAsyncTask failed.", e);
+            }
             mTextView.removeCallbacks(onTimeOut);
             return result;
         }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 98f8087..2357f36 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,10 +17,10 @@
 package android.widget;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.view.OnReceiveContentListener.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_CLIPBOARD;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_PROCESS_TEXT;
+import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_CLIPBOARD;
+import static android.view.ContentInfo.SOURCE_PROCESS_TEXT;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
@@ -146,6 +146,7 @@
 import android.view.AccessibilityIterators.TextSegmentIterator;
 import android.view.ActionMode;
 import android.view.Choreographer;
+import android.view.ContentInfo;
 import android.view.ContextMenu;
 import android.view.DragEvent;
 import android.view.Gravity;
@@ -154,7 +155,6 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
-import android.view.OnReceiveContentListener.Payload;
 import android.view.PointerIcon;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -2151,7 +2151,8 @@
                 if (result != null) {
                     if (isTextEditable()) {
                         ClipData clip = ClipData.newPlainText("", result);
-                        Payload payload = new Payload.Builder(clip, SOURCE_PROCESS_TEXT).build();
+                        ContentInfo payload =
+                                new ContentInfo.Builder(clip, SOURCE_PROCESS_TEXT).build();
                         performReceiveContent(payload);
                         if (mEditor != null) {
                             mEditor.refreshTextActionMode();
@@ -11857,7 +11858,7 @@
                     + " cannot be autofilled into " + this);
             return;
         }
-        final Payload payload = new Payload.Builder(clip, SOURCE_AUTOFILL).build();
+        final ContentInfo payload = new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
         performReceiveContent(payload);
     }
 
@@ -12924,7 +12925,7 @@
         if (clip == null) {
             return;
         }
-        final Payload payload = new Payload.Builder(clip, SOURCE_CLIPBOARD)
+        final ContentInfo payload = new ContentInfo.Builder(clip, SOURCE_CLIPBOARD)
                 .setFlags(withFormatting ? 0 : FLAG_CONVERT_TO_PLAIN_TEXT)
                 .build();
         performReceiveContent(payload);
@@ -13740,8 +13741,9 @@
      * @return The portion of the passed-in content that was not handled (may be all, some, or none
      * of the passed-in content).
      */
+    @Nullable
     @Override
-    public @Nullable Payload onReceiveContent(@NonNull Payload payload) {
+    public ContentInfo onReceiveContent(@NonNull ContentInfo payload) {
         if (mEditor != null) {
             return mEditor.getDefaultOnReceiveContentListener().onReceiveContent(this, payload);
         }
diff --git a/core/java/android/widget/TextViewOnReceiveContentListener.java b/core/java/android/widget/TextViewOnReceiveContentListener.java
index 7ef68ec..8cef106 100644
--- a/core/java/android/widget/TextViewOnReceiveContentListener.java
+++ b/core/java/android/widget/TextViewOnReceiveContentListener.java
@@ -17,10 +17,10 @@
 package android.widget;
 
 import static android.content.ContentResolver.SCHEME_CONTENT;
-import static android.view.OnReceiveContentListener.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
+import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
+import static android.view.ContentInfo.SOURCE_INPUT_METHOD;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -38,9 +38,10 @@
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.util.Log;
+import android.view.ContentInfo;
+import android.view.ContentInfo.Flags;
+import android.view.ContentInfo.Source;
 import android.view.OnReceiveContentListener;
-import android.view.OnReceiveContentListener.Payload.Flags;
-import android.view.OnReceiveContentListener.Payload.Source;
 import android.view.View;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -53,20 +54,21 @@
 import java.util.Arrays;
 
 /**
- * Default implementation of {@link OnReceiveContentListener} for editable
- * {@link TextView} components. This class handles insertion of text (plain text, styled text, HTML,
- * etc) but not images or other content.
+ * Default implementation for {@link View#onReceiveContent} for editable {@link TextView}
+ * components. This class handles insertion of text (plain text, styled text, HTML, etc) but not
+ * images or other content.
  *
  * @hide
  */
 @VisibleForTesting
 public final class TextViewOnReceiveContentListener implements OnReceiveContentListener {
-    private static final String LOG_TAG = "OnReceiveContent";
+    private static final String LOG_TAG = "ReceiveContent";
 
     @Nullable private InputConnectionInfo mInputConnectionInfo;
 
+    @Nullable
     @Override
-    public @Nullable Payload onReceiveContent(@NonNull View view, @NonNull Payload payload) {
+    public ContentInfo onReceiveContent(@NonNull View view, @NonNull ContentInfo payload) {
         if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
             Log.d(LOG_TAG, "onReceive: " + payload);
         }
@@ -126,7 +128,7 @@
         editable.replace(start, end, replacement);
     }
 
-    private void onReceiveForAutofill(@NonNull TextView view, @NonNull Payload payload) {
+    private void onReceiveForAutofill(@NonNull TextView view, @NonNull ContentInfo payload) {
         ClipData clip = payload.getClip();
         if (isUsageOfImeCommitContentEnabled(view)) {
             clip = handleNonTextViaImeCommitContent(clip);
@@ -145,7 +147,8 @@
         Selection.setSelection(editable, editable.length());
     }
 
-    private static void onReceiveForDragAndDrop(@NonNull TextView view, @NonNull Payload payload) {
+    private static void onReceiveForDragAndDrop(@NonNull TextView view,
+            @NonNull ContentInfo payload) {
         final CharSequence text = coerceToText(payload.getClip(), view.getContext(),
                 payload.getFlags());
         replaceSelection((Editable) view.getText(), text);
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 6e20452..1ac188c 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -101,6 +101,19 @@
     public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;
 
     /**
+     * Last possible vendor specific display area id.
+     * @hide
+     */
+    public static final int FEATURE_VENDOR_LAST = FEATURE_VENDOR_FIRST + 10_000;
+
+    /**
+     * Task display areas that can be created at runtime start with this value.
+     * @see #createTaskDisplayArea(int, int, String)
+     * @hide
+     */
+    public static final int FEATURE_RUNTIME_TASK_CONTAINER_FIRST = FEATURE_VENDOR_LAST + 1;
+
+    /**
      * Registers a DisplayAreaOrganizer to manage display areas for a given feature. A feature can
      * not be registered by multiple organizers at the same time.
      *
@@ -132,6 +145,50 @@
     }
 
     /**
+     * Creates a persistent task display area. It will be added to be the top most task display area
+     * in the root.
+     *
+     * The new created TDA is organized by the organizer, and will be deleted on calling
+     * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
+     *
+     * @param displayId the display to create the new task display area in.
+     * @param rootFeatureId the root display area to create the new task display area in. Caller can
+     *                      use {@link #FEATURE_ROOT} as the root of the logical display.
+     * @param name the name for the new task display area.
+     * @return the new created task display area.
+     * @throws IllegalArgumentException if failed to create a new task display area.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+    @CallSuper
+    @NonNull
+    public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int rootFeatureId,
+            @NonNull String name) {
+        try {
+            return getController().createTaskDisplayArea(
+                    mInterface, displayId, rootFeatureId, name);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Deletes a persistent task display area. It can only be one that created by an organizer.
+     *
+     * @throws IllegalArgumentException if failed to delete the task display area.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+    @CallSuper
+    public void deleteTaskDisplayArea(@NonNull WindowContainerToken taskDisplayArea) {
+        try {
+            getController().deleteTaskDisplayArea(taskDisplayArea);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called when a DisplayArea of the registered window type can be controlled by this organizer.
      * It will not be called for the DisplayAreas that exist when {@link #registerOrganizer(int)} is
      * called.
diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl
index edabcf8..26fa434 100644
--- a/core/java/android/window/IDisplayAreaOrganizerController.aidl
+++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl
@@ -19,6 +19,7 @@
 import android.content.pm.ParceledListSlice;
 import android.window.DisplayAreaAppearedInfo;
 import android.window.IDisplayAreaOrganizer;
+import android.window.WindowContainerToken;
 
 /** @hide */
 interface IDisplayAreaOrganizerController {
@@ -37,4 +38,28 @@
      * Unregisters a previously registered display area organizer.
      */
     void unregisterOrganizer(in IDisplayAreaOrganizer organizer);
+
+    /**
+     * Creates a persistent task display area. It will be added to be the top most task display area
+     * in the root.
+     *
+     * The new created TDA is organized by the organizer, and will be deleted on calling
+     * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
+     *
+     * @param displayId the display to create the new task display area in.
+     * @param rootFeatureId the root display area to create the new task display area in. Caller can
+     *                      use {@link #FEATURE_ROOT} as the root of the logical display.
+     * @param name the name for the new task display area.
+     * @return the new created task display area.
+     * @throws IllegalArgumentException if failed to create a new task display area.
+     */
+    DisplayAreaAppearedInfo createTaskDisplayArea(in IDisplayAreaOrganizer organizer, int displayId,
+        int rootFeatureId, in String name);
+
+    /**
+     * Deletes a persistent task display area. It can only be one that created by an organizer.
+     *
+     * @throws IllegalArgumentException if failed to delete the task display area.
+     */
+    void deleteTaskDisplayArea(in WindowContainerToken taskDisplayArea);
 }
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 0eef847..b4e7d6a 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -66,6 +67,9 @@
     private final @WindowManager.TransitionOldType int mType;
     private final ArrayList<Change> mChanges = new ArrayList<>();
 
+    private SurfaceControl mRootLeash;
+    private final Point mRootOffset = new Point();
+
     /** @hide */
     public TransitionInfo(@WindowManager.TransitionOldType int type) {
         mType = type;
@@ -74,6 +78,9 @@
     private TransitionInfo(Parcel in) {
         mType = in.readInt();
         in.readList(mChanges, null /* classLoader */);
+        mRootLeash = new SurfaceControl();
+        mRootLeash.readFromParcel(in);
+        mRootOffset.readFromParcel(in);
     }
 
     @Override
@@ -81,6 +88,8 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mType);
         dest.writeList(mChanges);
+        mRootLeash.writeToParcel(dest, flags);
+        mRootOffset.writeToParcel(dest, flags);
     }
 
     @NonNull
@@ -103,10 +112,35 @@
         return 0;
     }
 
+    /** @see #getRootLeash() */
+    public void setRootLeash(@NonNull SurfaceControl leash, int offsetLeft, int offsetTop) {
+        mRootLeash = leash;
+        mRootOffset.set(offsetLeft, offsetTop);
+    }
+
     public int getType() {
         return mType;
     }
 
+    /**
+     * @return a surfacecontrol that can serve as a parent surfacecontrol for all the changing
+     * participants to animate within. This will generally be placed at the highest-z-order
+     * shared ancestor of all participants.
+     */
+    @NonNull
+    public SurfaceControl getRootLeash() {
+        if (mRootLeash == null) {
+            throw new IllegalStateException("Trying to get a leash which wasn't set");
+        }
+        return mRootLeash;
+    }
+
+    /** @return the offset (relative to the screen) of the root leash. */
+    @NonNull
+    public Point getRootOffset() {
+        return mRootOffset;
+    }
+
     @NonNull
     public List<Change> getChanges() {
         return mChanges;
@@ -136,7 +170,7 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("{t=" + mType + " c=[");
+        sb.append("{t=" + mType + " ro=" + mRootOffset + " c=[");
         for (int i = 0; i < mChanges.size(); ++i) {
             if (i > 0) {
                 sb.append(',');
@@ -167,8 +201,9 @@
         private WindowContainerToken mParent;
         private final SurfaceControl mLeash;
         private int mMode = TRANSIT_NONE;
-        private final Rect mStartBounds = new Rect();
-        private final Rect mEndBounds = new Rect();
+        private final Rect mStartAbsBounds = new Rect();
+        private final Rect mEndAbsBounds = new Rect();
+        private final Point mEndRelOffset = new Point();
 
         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
             mContainer = container;
@@ -181,8 +216,9 @@
             mLeash = new SurfaceControl();
             mLeash.readFromParcel(in);
             mMode = in.readInt();
-            mStartBounds.readFromParcel(in);
-            mEndBounds.readFromParcel(in);
+            mStartAbsBounds.readFromParcel(in);
+            mEndAbsBounds.readFromParcel(in);
+            mEndRelOffset.readFromParcel(in);
         }
 
         /** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -195,14 +231,19 @@
             mMode = mode;
         }
 
-        /** Sets the bounds this container occupied before the change */
-        public void setStartBounds(@Nullable Rect rect) {
-            mStartBounds.set(rect);
+        /** Sets the bounds this container occupied before the change in screen space */
+        public void setStartAbsBounds(@Nullable Rect rect) {
+            mStartAbsBounds.set(rect);
         }
 
-        /** Sets the bounds this container will occupy after the change */
-        public void setEndBounds(@Nullable Rect rect) {
-            mEndBounds.set(rect);
+        /** Sets the bounds this container will occupy after the change in screen space */
+        public void setEndAbsBounds(@Nullable Rect rect) {
+            mEndAbsBounds.set(rect);
+        }
+
+        /** Sets the offset of this container from its parent surface */
+        public void setEndRelOffset(int left, int top) {
+            mEndRelOffset.set(left, top);
         }
 
         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
@@ -230,8 +271,8 @@
          * is coming into existence.
          */
         @NonNull
-        public Rect getStartBounds() {
-            return mStartBounds;
+        public Rect getStartAbsBounds() {
+            return mStartAbsBounds;
         }
 
         /**
@@ -239,8 +280,16 @@
          * is disappearing.
          */
         @NonNull
-        public Rect getEndBounds() {
-            return mEndBounds;
+        public Rect getEndAbsBounds() {
+            return mEndAbsBounds;
+        }
+
+        /**
+         * @return the offset of the container's surface from its parent surface after the change.
+         */
+        @NonNull
+        public Point getEndRelOffset() {
+            return mEndRelOffset;
         }
 
         /** @return the leash or surface to animate for this container */
@@ -256,8 +305,9 @@
             dest.writeTypedObject(mParent, flags);
             mLeash.writeToParcel(dest, flags);
             dest.writeInt(mMode);
-            mStartBounds.writeToParcel(dest, flags);
-            mEndBounds.writeToParcel(dest, flags);
+            mStartAbsBounds.writeToParcel(dest, flags);
+            mEndAbsBounds.writeToParcel(dest, flags);
+            mEndRelOffset.writeToParcel(dest, flags);
         }
 
         @NonNull
@@ -283,8 +333,8 @@
         @Override
         public String toString() {
             return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
-                    + " m=" + modeToString(mMode) + " sb=" + mStartBounds
-                    + " eb=" + mEndBounds + "}";
+                    + " m=" + modeToString(mMode) + " sb=" + mStartAbsBounds
+                    + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + "}";
         }
     }
 }
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
index 7a87be3..b9d3df6 100644
--- a/core/java/com/android/internal/compat/ChangeReporter.java
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -223,7 +223,7 @@
                     FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER;
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, prefix = { "STATE_" }, value = {
+    @IntDef(prefix = { "STATE_" }, value = {
             STATE_UNKNOWN_STATE,
             STATE_ENABLED,
             STATE_DISABLED,
@@ -233,7 +233,7 @@
     }
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, prefix = { "SOURCE_" }, value = {
+    @IntDef(prefix = { "SOURCE_" }, value = {
             SOURCE_UNKNOWN_SOURCE,
             SOURCE_APP_PROCESS,
             SOURCE_SYSTEM_SERVER
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 3b5fecf..0ede1b8 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -20,15 +20,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
-import android.database.DatabaseUtils;
 import android.database.MatrixCursor;
 import android.database.MatrixCursor.RowBuilder;
 import android.graphics.Point;
 import android.net.Uri;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.FileObserver;
@@ -39,7 +38,6 @@
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
-import android.provider.MediaStore.Files.FileColumns;
 import android.provider.MetadataReader;
 import android.system.Int64Ref;
 import android.text.TextUtils;
@@ -66,6 +64,7 @@
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Predicate;
@@ -271,8 +270,7 @@
                 throw new IllegalStateException("Failed to touch " + file + ": " + e);
             }
         }
-        MediaStore.scanFile(getContext().getContentResolver(), file);
-
+        updateMediaStore(getContext(), file);
         return childId;
     }
 
@@ -295,7 +293,9 @@
         onDocIdChanged(afterDocId);
 
         final File afterVisibleFile = getFileForDocId(afterDocId, true);
-        moveInMediaStore(beforeVisibleFile, afterVisibleFile);
+
+        updateMediaStore(getContext(), beforeVisibleFile);
+        updateMediaStore(getContext(), afterVisibleFile);
 
         if (!TextUtils.equals(docId, afterDocId)) {
             return afterDocId;
@@ -323,17 +323,23 @@
         onDocIdChanged(sourceDocumentId);
         onDocIdDeleted(sourceDocumentId);
         onDocIdChanged(docId);
-        moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true));
-
+        // update the database
+        updateMediaStore(getContext(), visibleFileBefore);
+        updateMediaStore(getContext(), getFileForDocId(docId, true));
         return docId;
     }
 
-    private void moveInMediaStore(@Nullable File oldVisibleFile, @Nullable File newVisibleFile) {
-        if (oldVisibleFile != null) {
-            MediaStore.scanFile(getContext().getContentResolver(), oldVisibleFile);
-        }
-        if (newVisibleFile != null) {
-            MediaStore.scanFile(getContext().getContentResolver(), newVisibleFile);
+    private static void updateMediaStore(@NonNull Context context, File file) {
+        if (file != null) {
+            final ContentResolver resolver = context.getContentResolver();
+            final String noMedia = ".nomedia";
+            // For file, check whether the file name is .nomedia or not.
+            // If yes, scan the parent directory to update all files in the directory.
+            if (!file.isDirectory() && file.getName().toLowerCase(Locale.ROOT).endsWith(noMedia)) {
+                MediaStore.scanFile(resolver, file.getParentFile());
+            } else {
+                MediaStore.scanFile(resolver, file);
+            }
         }
     }
 
@@ -354,35 +360,7 @@
 
         onDocIdChanged(docId);
         onDocIdDeleted(docId);
-        removeFromMediaStore(visibleFile);
-    }
-
-    private void removeFromMediaStore(@Nullable File visibleFile)
-            throws FileNotFoundException {
-        // visibleFolder is null if we're removing a document from external thumb drive or SD card.
-        if (visibleFile != null) {
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                final ContentResolver resolver = getContext().getContentResolver();
-                final Uri externalUri = MediaStore.Files.getContentUri("external");
-                final Bundle queryArgs = new Bundle();
-                queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_INCLUDE);
-
-                // Remove the media store entry corresponding to visibleFile and if it is a
-                // directory, also remove media store entries for any files inside this directory.
-                // Logic borrowed from com.android.providers.media.scan.ModernMediaScanner.
-                final String pathEscapedForLike = DatabaseUtils.escapeForLike(
-                        visibleFile.getAbsolutePath());
-                ContentResolver.includeSqlSelectionArgs(queryArgs,
-                        FileColumns.DATA + " LIKE ? ESCAPE '\\' OR "
-                                + FileColumns.DATA + " LIKE ? ESCAPE '\\'",
-                        new String[] {pathEscapedForLike + "/%", pathEscapedForLike});
-                resolver.delete(externalUri, queryArgs);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
+        updateMediaStore(getContext(), visibleFile);
     }
 
     @Override
diff --git a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
index 70505bc..6c01780 100644
--- a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
@@ -33,7 +33,10 @@
  *
  * @param <S> the concrete remote service class
  * @param <I> the interface of the binder service
+ *
+ * @deprecated Use {@link ServiceConnector} to manage remote service connections
  */
+@Deprecated
 public abstract class AbstractMultiplePendingRequestsRemoteService<S
         extends AbstractMultiplePendingRequestsRemoteService<S, I>, I extends IInterface>
         extends AbstractRemoteService<S, I> {
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 722e5c1..f63ac2e 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -58,9 +58,12 @@
  * @param <S> the concrete remote service class
  * @param <I> the interface of the binder service
  *
+ * @deprecated Use {@link ServiceConnector} to manage remote service connections
+ *
  * @hide
  */
 //TODO(b/117779333): improve javadoc above instead of using Autofill as an example
+@Deprecated
 public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>,
         I extends IInterface> implements DeathRecipient {
     private static final int MSG_BIND = 1;
diff --git a/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
index 2ebf2fd..0d9af8c 100644
--- a/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
@@ -33,8 +33,11 @@
  * @param <S> the concrete remote service class
  * @param <I> the interface of the binder service
  *
+ * @deprecated Use {@link ServiceConnector} to manage remote service connections
+ *
  * @hide
  */
+@Deprecated
 public abstract class AbstractSinglePendingRequestRemoteService<S
         extends AbstractSinglePendingRequestRemoteService<S, I>, I extends IInterface>
         extends AbstractRemoteService<S, I> {
diff --git a/core/java/com/android/internal/infra/OWNERS b/core/java/com/android/internal/infra/OWNERS
new file mode 100644
index 0000000..4550358
--- /dev/null
+++ b/core/java/com/android/internal/infra/OWNERS
@@ -0,0 +1,6 @@
+per-file AndroidFuture.java = eugenesusla@google.com
+per-file RemoteStream.java = eugenesusla@google.com
+per-file PerUser.java = eugenesusla@google.com
+per-file ServiceConnector.java = eugenesusla@google.com
+per-file AndroidFuture.aidl = eugenesusla@google.com
+per-file IAndroidFuture.aidl = eugenesusla@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
new file mode 100644
index 0000000..ec67792
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.os.RemoteException;
+
+import com.android.internal.view.InputBindResult;
+
+import java.util.function.Supplier;
+
+/**
+ * Defines a set of helper methods to callback corresponding results in {@link ResultCallbacks}.
+ */
+public final class CallbackUtils {
+
+    /**
+     * Not intended to be instantiated.
+     */
+    private CallbackUtils() {
+    }
+
+    /**
+     * A utility method using given {@link IInputBindResultResultCallback} to callback the
+     * {@link InputBindResult}.
+     *
+     * @param callback {@link IInputBindResultResultCallback} to be called back.
+     * @param resultSupplier the supplier from which {@link InputBindResult} is provided.
+     */
+    @AnyThread
+    public static void onResult(@NonNull IInputBindResultResultCallback callback,
+            @NonNull Supplier<InputBindResult> resultSupplier) {
+        try {
+            callback.onResult(resultSupplier.get());
+        } catch (RemoteException ignored) { }
+    }
+}
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index 16473b9..b9e1cf0 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -19,6 +19,7 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -123,6 +124,16 @@
                 return true;
             }
         }
+
+        /**
+         * Blocks the calling thread until this object becomes ready to return the value.
+         */
+        @AnyThread
+        public void await() {
+            try {
+                mLatch.await();
+            } catch (InterruptedException ignored) { }
+        }
     }
 
     /**
@@ -249,6 +260,13 @@
     }
 
     /**
+     * @return an instance of {@link Completable.InputBindResult}.
+     */
+    public static Completable.InputBindResult createInputBindResult() {
+        return new Completable.InputBindResult();
+    }
+
+    /**
      * Completable object of {@link java.lang.Boolean}.
      */
     public static final class Boolean extends Values<java.lang.Boolean> { }
@@ -275,4 +293,65 @@
      */
     public static final class InputBindResult
             extends Values<com.android.internal.view.InputBindResult> { }
+
+    /**
+     * Await the result by the {@link Completable.Values}.
+     *
+     * @return the result once {@link ValueBase#onComplete()}
+     */
+    @AnyThread
+    @Nullable
+    public static <T> T getResult(@NonNull Completable.Values<T> value) {
+        value.await();
+        return value.getValue();
+    }
+
+    /**
+     * Await the result by the {@link Completable.Int}, and log it if there is no result after
+     * given timeout.
+     *
+     * @return the result once {@link ValueBase#onComplete()}
+     */
+    @AnyThread
+    public static int getResultOrZero(@NonNull Completable.Int value, String tag,
+            @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
+            int maxWaitTime) {
+        final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
+        if (value.hasValue()) {
+            return value.getValue();
+        }
+        logInternal(tag, methodName, timedOut, maxWaitTime, 0);
+        return 0;
+    }
+
+    /**
+     * Await the result by the {@link Completable.Values}, and log it if there is no result after
+     * given timeout.
+     *
+     * @return the result once {@link ValueBase#onComplete()}
+     */
+    @AnyThread
+    @Nullable
+    public static <T> T getResultOrNull(@NonNull Completable.Values<T> value, String tag,
+            @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
+            int maxWaitTime) {
+        final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
+        if (value.hasValue()) {
+            return value.getValue();
+        }
+        logInternal(tag, methodName, timedOut, maxWaitTime, null);
+        return null;
+    }
+
+    @AnyThread
+    private static void logInternal(String tag, @Nullable String methodName, boolean timedOut,
+            int maxWaitTime, @Nullable Object defaultValue) {
+        if (timedOut) {
+            Log.w(tag, methodName + " didn't respond in " + maxWaitTime + " msec."
+                    + " Returning default: " + defaultValue);
+        } else {
+            Log.w(tag, methodName + " was canceled before complete. Returning default: "
+                    + defaultValue);
+        }
+    }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt b/core/java/com/android/internal/inputmethod/IInputBindResultResultCallback.aidl
similarity index 75%
copy from tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
copy to core/java/com/android/internal/inputmethod/IInputBindResultResultCallback.aidl
index 6bc9dcb..b52b3b1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
+++ b/core/java/com/android/internal/inputmethod/IInputBindResultResultCallback.aidl
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+package com.android.internal.inputmethod;
 
-internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
+import com.android.internal.view.InputBindResult;
+
+oneway interface IInputBindResultResultCallback {
+    void onResult(in InputBindResult result);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index 7131284..c59dcf4 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -21,6 +21,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import com.android.internal.view.InputBindResult;
+
 import java.lang.ref.WeakReference;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -154,4 +156,31 @@
             }
         };
     }
+
+    /**
+     * Creates {@link IInputBindResultResultCallback.Stub} that is to set
+     * {@link Completable.InputBindResult} when receiving the result.
+     *
+     * @param value {@link Completable.InputBindResult} to be set when receiving the result.
+     * @return {@link IInputBindResultResultCallback.Stub} that can be passed as a binder IPC
+     *         parameter.
+     */
+    @AnyThread
+    public static IInputBindResultResultCallback.Stub of(
+            @NonNull Completable.InputBindResult value) {
+        final AtomicReference<WeakReference<Completable.InputBindResult>>
+                atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+        return new IInputBindResultResultCallback.Stub() {
+            @BinderThread
+            @Override
+            public void onResult(InputBindResult result) {
+                final Completable.InputBindResult value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onComplete(result);
+            }
+        };
+    }
 }
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index ffc7f05..1553e2e 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -48,7 +48,8 @@
         SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED,
         SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
         SoftInputShowHideReason.HIDE_BUBBLES,
-        SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR})
+        SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR,
+        SoftInputShowHideReason.HIDE_REMOVE_CLIENT})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -161,4 +162,9 @@
      * soft-input when the same window focused again to align with the same behavior prior to R.
      */
     int HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR = 20;
+
+    /**
+     * Hide soft input when a {@link com.android.internal.view.IInputMethodClient} is removed.
+     */
+    int HIDE_REMOVE_CLIENT = 21;
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7c442b4..dcd74fd 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -38,6 +38,7 @@
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
+import android.os.BatteryProperty;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Build;
@@ -54,6 +55,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
@@ -98,6 +100,8 @@
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
+import com.android.internal.power.MeasuredEnergyArray;
+import com.android.internal.power.MeasuredEnergyStats;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -142,6 +146,14 @@
 public class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
     private static final boolean DEBUG = false;
+
+    // TODO(b/169376495): STOPSHIP if true
+    private static final boolean DEBUG_FOREGROUND_STATS = true;
+
+    private static final boolean ENABLE_FOREGROUND_STATS_COLLECTION =
+            DEBUG_FOREGROUND_STATS && SystemProperties.getBoolean(
+                    "debug.battery_foreground_stats_collection", false);
+
     public static final boolean DEBUG_ENERGY = false;
     private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
     private static final boolean DEBUG_BINDER_STATS = false;
@@ -155,7 +167,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 189 + (USE_OLD_HISTORY ? 1000 : 0);
+    static final int VERSION = 190 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -349,12 +361,20 @@
     }
 
     /** interface to update rail information for power monitor */
-    public interface RailEnergyDataCallback {
+    public interface MeasuredEnergyRetriever {
         /** Function to fill the map for the rail data stats
          * Used for power monitoring feature
          * @param railStats
          */
         void fillRailDataStats(RailStats railStats);
+        /**
+         * Function to get energy consumption data
+         *
+         * @return an array of measured energy (in microjoules) since boot, will be null if
+         * measured energy data is unavailable
+         */
+        @Nullable
+        MeasuredEnergyArray getEnergyConsumptionData();
     }
 
     public static abstract class UserInfoProvider {
@@ -391,7 +411,7 @@
         }
     };
 
-    public final RailEnergyDataCallback mRailEnergyDataCallback;
+    public final MeasuredEnergyRetriever mMeasuredEnergyRetriever;
 
     /**
      * This handler is running on {@link BackgroundThread}.
@@ -624,8 +644,10 @@
         int UPDATE_WIFI = 0x02;
         int UPDATE_RADIO = 0x04;
         int UPDATE_BT = 0x08;
-        int UPDATE_RPM = 0x10; // 16
-        int UPDATE_ALL = UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM;
+        int UPDATE_RPM = 0x10;
+        int UPDATE_ENERGY = 0x20;
+        int UPDATE_ALL =
+                UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM | UPDATE_ENERGY;
 
         Future<?> scheduleSync(String reason, int flags);
         Future<?> scheduleCpuSyncDueToRemovedUid(int uid);
@@ -633,8 +655,11 @@
                 long delayMillis);
         Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
         Future<?> scheduleCpuSyncDueToSettingChange();
-        Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery,
-                boolean onBatteryScreenOff);
+        /**
+         * Schedule a sync because of a screen state change.
+         */
+        Future<?> scheduleSyncDueToScreenStateChange(int flags, boolean onBattery,
+                boolean onBatteryScreenOff, int screenState);
         Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
         void cancelCpuSyncDueToWakelockChange();
         Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis);
@@ -724,6 +749,37 @@
     long mTrackRunningHistoryElapsedRealtimeMs = 0;
     long mTrackRunningHistoryUptimeMs = 0;
 
+    private static final int FOREGROUND_UID_INITIAL_CAPACITY = 10;
+    private static final int INVALID_UID = -1;
+
+    private final IntArray mForegroundUids = ENABLE_FOREGROUND_STATS_COLLECTION
+            ? new IntArray(FOREGROUND_UID_INITIAL_CAPACITY) :  null;
+
+    // Last recorded battery energy capacity.
+    // This is used for computing foregrund power per application.
+    // See: PowerForUid below
+    private long mLastBatteryEnergyCapacityNWh = 0;
+
+    private static final class PowerForUid {
+        public long energyNwh = 0;
+        // Same as energyNwh, but not tracked for the first 2 minutes;
+        public long filteredEnergyNwh = 0;
+        public double totalHours = 0;
+        public long baseTimeMs = 0;
+
+        double computePower() {
+            // units in nW
+            return totalHours != 0 ? energyNwh / totalHours : -1.0;
+        }
+
+        double computeFilteredPower() {
+            // units in nW
+            return totalHours != 0 ? filteredEnergyNwh / totalHours : -1.0;
+        }
+    }
+    private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION
+            ? new HashMap<>() : null;
+
     final BatteryStatsHistory mBatteryStatsHistory;
 
     final HistoryItem mHistoryCur = new HistoryItem();
@@ -932,6 +988,13 @@
     int mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
 
     /**
+     * Accumulated energy consumption of various consumers while on battery.
+     * If energy consumer data is unavailable this will be null.
+     */
+    @GuardedBy("this")
+    MeasuredEnergyStats mBatteryMeasuredEnergyStats;
+
+    /**
      * These provide time bases that discount the time the device is plugged
      * in to power.
      */
@@ -1004,6 +1067,8 @@
 
     private int mNumConnectivityChange;
 
+    private int mBatteryVolt = -1;
+    private int mBatteryCharge = -1;
     private int mEstimatedBatteryCapacity = -1;
 
     private int mMinLearnedBatteryCapacity = -1;
@@ -1123,7 +1188,7 @@
         mBatteryStatsHistory = null;
         mHandler = null;
         mPlatformIdleStateCallback = null;
-        mRailEnergyDataCallback = null;
+        mMeasuredEnergyRetriever = null;
         mUserInfoProvider = null;
         mConstants = new Constants(mHandler);
         clearHistoryLocked();
@@ -1424,7 +1489,8 @@
          * @param in the parcel to read from
          * @return the Counter or null.
          */
-        public static @Nullable Counter readCounterFromParcel(TimeBase timeBase, Parcel in) {
+        @Nullable
+        public static Counter readCounterFromParcel(TimeBase timeBase, Parcel in) {
             if (in.readInt() == 0) {
                 return null;
             }
@@ -3949,7 +4015,7 @@
     @GuardedBy("this")
     public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptimeUs,
             long realtimeUs) {
-        final boolean screenOff = !isScreenOn(screenState);
+        final boolean screenOff = !Display.isOnState(screenState);
         final boolean updateOnBatteryTimeBase = unplugged != mOnBatteryTimeBase.isRunning();
         final boolean updateOnBatteryScreenOffTimeBase =
                 (unplugged && screenOff) != mOnBatteryScreenOffTimeBase.isRunning();
@@ -4131,6 +4197,49 @@
         // TODO(b/155216561): It is possible for isolated uids to be in a higher
         // state than its parent uid. We should track the highest state within the union of host
         // and isolated uids rather than only the parent uid.
+
+
+        int uidState = mapToInternalProcessState(state);
+
+        boolean isForeground = (uidState == Uid.PROCESS_STATE_TOP)
+                ||  (uidState == Uid.PROCESS_STATE_FOREGROUND);
+
+
+        if (ENABLE_FOREGROUND_STATS_COLLECTION) {
+            boolean previouslyInForegrond = false;
+            for (int i = 0; i < mForegroundUids.size(); i++) {
+                if (mForegroundUids.get(i) == uid) {
+                    previouslyInForegrond = true;
+                    if (!isForeground) {
+                        // If we were previously in the foreground, remove the uid
+                        // from the foreground set and dirty the slot.
+                        mForegroundUids.set(i, INVALID_UID);
+                        final PowerForUid pfu =
+                                mUidToPower.computeIfAbsent(uid, unused -> new PowerForUid());
+                        pfu.baseTimeMs = 0;
+                        break;
+                    }
+                }
+            }
+
+            if (!previouslyInForegrond && isForeground) {
+                boolean addedToForeground = false;
+                // Check if we have a free slot to clobber...
+                for (int i = 0; i < mForegroundUids.size(); i++) {
+                    if (mForegroundUids.get(i) == INVALID_UID) {
+                        addedToForeground = true;
+                        mForegroundUids.set(i, uid);
+                        break;
+                    }
+                }
+
+                // ...if not, append to the end of the array.
+                if (!addedToForeground) {
+                    mForegroundUids.add(uid);
+                }
+            }
+        }
+
         FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid,
                 ActivityManager.processStateAmToProto(state));
         getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
@@ -5012,16 +5121,16 @@
             }
 
             boolean updateHistory = false;
-            if (isScreenDoze(state) && !isScreenDoze(oldState)) {
+            if (Display.isDozeState(state) && !Display.isDozeState(oldState)) {
                 mHistoryCur.states |= HistoryItem.STATE_SCREEN_DOZE_FLAG;
                 mScreenDozeTimer.startRunningLocked(elapsedRealtimeMs);
                 updateHistory = true;
-            } else if (isScreenDoze(oldState) && !isScreenDoze(state)) {
+            } else if (Display.isDozeState(oldState) && !Display.isDozeState(state)) {
                 mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_DOZE_FLAG;
                 mScreenDozeTimer.stopRunningLocked(elapsedRealtimeMs);
                 updateHistory = true;
             }
-            if (isScreenOn(state)) {
+            if (Display.isOnState(state)) {
                 mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
                         + Integer.toHexString(mHistoryCur.states));
@@ -5031,7 +5140,7 @@
                             .startRunningLocked(elapsedRealtimeMs);
                 }
                 updateHistory = true;
-            } else if (isScreenOn(oldState)) {
+            } else if (Display.isOnState(oldState)) {
                 mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
                         + Integer.toHexString(mHistoryCur.states));
@@ -5047,15 +5156,21 @@
                         + Display.stateToString(state));
                 addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             }
-            mExternalSync.scheduleCpuSyncDueToScreenStateChange(
-                    mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning());
-            if (isScreenOn(state)) {
+            int updateFlag = ExternalStatsSync.UPDATE_CPU;
+            if (mBatteryMeasuredEnergyStats != null && mBatteryMeasuredEnergyStats.hasSubsystem(
+                    MeasuredEnergyArray.SUBSYSTEM_DISPLAY)) {
+                updateFlag |= ExternalStatsSync.UPDATE_ENERGY;
+            }
+            mExternalSync.scheduleSyncDueToScreenStateChange(updateFlag,
+                    mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning(),
+                    mScreenState);
+            if (Display.isOnState(state)) {
                 updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
                         uptimeMs * 1000, elapsedRealtimeMs * 1000);
                 // Fake a wake lock, so we consider the device waked as long as the screen is on.
                 noteStartWakeLocked(-1, -1, null, "screen", null, WAKE_TYPE_PARTIAL, false,
                         elapsedRealtimeMs, uptimeMs);
-            } else if (isScreenOn(oldState)) {
+            } else if (Display.isOnState(oldState)) {
                 noteStopWakeLocked(-1, -1, null, "screen", "screen", WAKE_TYPE_PARTIAL,
                         elapsedRealtimeMs, uptimeMs);
                 updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
@@ -7039,6 +7154,26 @@
         }
     }
 
+    @Override
+    public long getScreenOnEnergy() {
+        if (mBatteryMeasuredEnergyStats == null || !mBatteryMeasuredEnergyStats.hasSubsystem(
+                MeasuredEnergyArray.SUBSYSTEM_DISPLAY)) {
+            return ENERGY_DATA_UNAVAILABLE;
+        }
+        return mBatteryMeasuredEnergyStats.getAccumulatedBucketEnergy(
+                MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON);
+    }
+
+    @Override
+    public long getScreenDozeEnergy() {
+        if (mBatteryMeasuredEnergyStats == null || !mBatteryMeasuredEnergyStats.hasSubsystem(
+                MeasuredEnergyArray.SUBSYSTEM_DISPLAY)) {
+            return ENERGY_DATA_UNAVAILABLE;
+        }
+        return mBatteryMeasuredEnergyStats.getAccumulatedBucketEnergy(
+                MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE);
+    }
+
     @Override public long getStartClockTime() {
         final long currentTimeMs = System.currentTimeMillis();
         if ((currentTimeMs > MILLISECONDS_IN_YEAR
@@ -10457,12 +10592,12 @@
     }
 
     public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
-            RailEnergyDataCallback railStatsCb, UserInfoProvider userInfoProvider) {
-        this(new SystemClocks(), systemDir, handler, cb, railStatsCb, userInfoProvider);
+            MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
+        this(new SystemClocks(), systemDir, handler, cb, energyStatsCb, userInfoProvider);
     }
 
     private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
-            PlatformIdleStateCallback cb, RailEnergyDataCallback railStatsCb,
+            PlatformIdleStateCallback cb, MeasuredEnergyRetriever energyStatsCb,
             UserInfoProvider userInfoProvider) {
         init(clocks);
 
@@ -10563,12 +10698,19 @@
         clearHistoryLocked();
         updateDailyDeadlineLocked();
         mPlatformIdleStateCallback = cb;
-        mRailEnergyDataCallback = railStatsCb;
+        mMeasuredEnergyRetriever = energyStatsCb;
         mUserInfoProvider = userInfoProvider;
 
         // Notify statsd that the system is initially not in doze.
         mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
         FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
+
+        final MeasuredEnergyArray energyStats = mMeasuredEnergyRetriever.getEnergyConsumptionData();
+        // If measured energy is not available, it is not supported and
+        // mBatteryMeasuredEnergyStats should be left null.
+        if (energyStats != null) {
+            mBatteryMeasuredEnergyStats = new MeasuredEnergyStats(energyStats, mScreenState);
+        }
     }
 
     @UnsupportedAppUsage
@@ -10588,7 +10730,7 @@
         mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
         readFromParcel(p);
         mPlatformIdleStateCallback = null;
-        mRailEnergyDataCallback = null;
+        mMeasuredEnergyRetriever = null;
     }
 
     public void setPowerProfileLocked(PowerProfile profile) {
@@ -11097,19 +11239,6 @@
         return mCharging;
     }
 
-    public boolean isScreenOn(int state) {
-        return state == Display.STATE_ON || state == Display.STATE_VR
-            || state == Display.STATE_ON_SUSPEND;
-    }
-
-    public boolean isScreenOff(int state) {
-        return state == Display.STATE_OFF;
-    }
-
-    public boolean isScreenDoze(int state) {
-        return state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND;
-    }
-
     void initTimes(long uptimeUs, long realtimeUs) {
         mStartClockTimeMs = System.currentTimeMillis();
         mOnBatteryTimeBase.init(uptimeUs, realtimeUs);
@@ -11152,11 +11281,11 @@
         mOnBatteryTimeBase.reset(uptimeUs, realtimeUs);
         mOnBatteryScreenOffTimeBase.reset(uptimeUs, realtimeUs);
         if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
-            if (isScreenOn(mScreenState)) {
+            if (Display.isOnState(mScreenState)) {
                 mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
                 mDischargeScreenDozeUnplugLevel = 0;
                 mDischargeScreenOffUnplugLevel = 0;
-            } else if (isScreenDoze(mScreenState)) {
+            } else if (Display.isDozeState(mScreenState)) {
                 mDischargeScreenOnUnplugLevel = 0;
                 mDischargeScreenDozeUnplugLevel = mHistoryCur.batteryLevel;
                 mDischargeScreenOffUnplugLevel = 0;
@@ -11286,6 +11415,11 @@
 
         mTmpRailStats.reset();
 
+        if (mBatteryMeasuredEnergyStats != null) {
+            mBatteryMeasuredEnergyStats.reset();
+            mExternalSync.scheduleSync("reset", ExternalStatsSync.UPDATE_ENERGY);
+        }
+
         resetIfNotNull(mSystemServerCpuTimesUs, false, elapsedRealtimeUs);
         resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
         resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
@@ -11339,19 +11473,19 @@
     }
 
     private void updateOldDischargeScreenLevelLocked(int state) {
-        if (isScreenOn(state)) {
+        if (Display.isOnState(state)) {
             int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
             if (diff > 0) {
                 mDischargeAmountScreenOn += diff;
                 mDischargeAmountScreenOnSinceCharge += diff;
             }
-        } else if (isScreenDoze(state)) {
+        } else if (Display.isDozeState(state)) {
             int diff = mDischargeScreenDozeUnplugLevel - mDischargeCurrentLevel;
             if (diff > 0) {
                 mDischargeAmountScreenDoze += diff;
                 mDischargeAmountScreenDozeSinceCharge += diff;
             }
-        } else if (isScreenOff(state)){
+        } else if (Display.isOffState(state)) {
             int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
             if (diff > 0) {
                 mDischargeAmountScreenOff += diff;
@@ -11361,15 +11495,15 @@
     }
 
     private void updateNewDischargeScreenLevelLocked(int state) {
-        if (isScreenOn(state)) {
+        if (Display.isOnState(state)) {
             mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
             mDischargeScreenOffUnplugLevel = 0;
             mDischargeScreenDozeUnplugLevel = 0;
-        } else if (isScreenDoze(state)){
+        } else if (Display.isDozeState(state)) {
             mDischargeScreenOnUnplugLevel = 0;
             mDischargeScreenDozeUnplugLevel = mDischargeCurrentLevel;
             mDischargeScreenOffUnplugLevel = 0;
-        } else if (isScreenOff(state)) {
+        } else if (Display.isOffState(state)) {
             mDischargeScreenOnUnplugLevel = 0;
             mDischargeScreenDozeUnplugLevel = 0;
             mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
@@ -12163,10 +12297,25 @@
      * Read and record Rail Energy data.
      */
     public void updateRailStatsLocked() {
-        if (mRailEnergyDataCallback == null || !mTmpRailStats.isRailStatsAvailable()) {
+        if (mMeasuredEnergyRetriever == null || !mTmpRailStats.isRailStatsAvailable()) {
             return;
         }
-        mRailEnergyDataCallback.fillRailDataStats(mTmpRailStats);
+        mMeasuredEnergyRetriever.fillRailDataStats(mTmpRailStats);
+    }
+
+    /**
+     * Get energy consumed (in microjoules) by a set of subsystems from the {@link
+     * MeasuredEnergyRetriever}, if available.
+     *
+     * @return a SparseLongArray that maps consumer id to energy consumed. Returns null if data is
+     * unavailable.
+     */
+    @Nullable
+    public MeasuredEnergyArray getEnergyConsumptionDataLocked() {
+        if (mMeasuredEnergyRetriever == null) {
+            return null;
+        }
+        return mMeasuredEnergyRetriever.getEnergyConsumptionData();
     }
 
     /**
@@ -12428,6 +12577,21 @@
     }
 
     /**
+     * Update energy consumption data with a new snapshot of energy data.
+     * Generally this should only be called from BatteryExternalStatsWorker.
+     *
+     * @param energyStats latest energy data to update with.
+     */
+    @GuardedBy("this")
+    public void updateMeasuredEnergyStatsLocked(@NonNull MeasuredEnergyArray energyStats,
+            int screenState) {
+        if (mBatteryMeasuredEnergyStats != null) {
+            mBatteryMeasuredEnergyStats.update(energyStats, screenState,
+                    mOnBatteryTimeBase.isRunning());
+        }
+    }
+
+    /**
      * Mark the current partial timers as gone through a collection so that they will be
      * considered in the next cpu times distribution to wakelock holders.
      */
@@ -12890,6 +13054,7 @@
                 doWrite = true;
                 resetAllStatsLocked(mSecUptime, mSecRealtime);
                 if (chargeUAh > 0 && level > 0) {
+                    mBatteryCharge = chargeUAh;
                     // Only use the reported coulomb charge value if it is supported and reported.
                     mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0));
                 }
@@ -12919,11 +13084,11 @@
             }
             addHistoryRecordLocked(mSecRealtime, mSecUptime);
             mDischargeCurrentLevel = mDischargeUnplugLevel = level;
-            if (isScreenOn(screenState)) {
+            if (Display.isOnState(screenState)) {
                 mDischargeScreenOnUnplugLevel = level;
                 mDischargeScreenDozeUnplugLevel = 0;
                 mDischargeScreenOffUnplugLevel = 0;
-            } else if (isScreenDoze(screenState)) {
+            } else if (Display.isDozeState(screenState)) {
                 mDischargeScreenOnUnplugLevel = 0;
                 mDischargeScreenDozeUnplugLevel = level;
                 mDischargeScreenOffUnplugLevel = 0;
@@ -13062,6 +13227,47 @@
                 startRecordingHistory(elapsedRealtimeMs, uptimeMs, true);
             }
         }
+
+        if (ENABLE_FOREGROUND_STATS_COLLECTION) {
+            mBatteryVolt = volt;
+            if (onBattery) {
+                final long energyNwh = (volt * (long) chargeUAh);
+                final long energyDelta = mLastBatteryEnergyCapacityNWh - energyNwh;
+                for (int i = 0; i < mForegroundUids.size(); i++) {
+                    final int uid = mForegroundUids.get(i);
+                    if (uid == INVALID_UID) {
+                        continue;
+                    }
+                    final PowerForUid pfu = mUidToPower
+                            .computeIfAbsent(uid, unused -> new PowerForUid());
+                    if (pfu.baseTimeMs <= 0) {
+                        pfu.baseTimeMs = currentTimeMs;
+                    } else {
+                        // Check if mLastBatteryEnergyCapacityNWh > energyNwh,
+                        // to make sure we only count discharges
+                        if (energyDelta > 0) {
+                            pfu.energyNwh += energyDelta;
+                            // Convert from milliseconds to hours
+                            // 1000 ms per second * 3600 seconds per hour
+                            pfu.totalHours += ((double) (currentTimeMs - pfu.baseTimeMs)
+                                    / (1.0 * 1000 * 60 * 60));
+                            // Now convert from 2 minutes to hours
+                            // 2 minutes = 1/30 of an hour
+                            if (pfu.totalHours > (2.0 / 60)) {
+                                pfu.filteredEnergyNwh += energyDelta;
+                            }
+
+                        }
+                        pfu.baseTimeMs = currentTimeMs;
+                    }
+                }
+                mLastBatteryEnergyCapacityNWh = energyNwh;
+            } else if (onBattery != mOnBattery) {
+                // Transition to onBattery = false
+                mUidToPower.values().forEach(v -> v.baseTimeMs = 0);
+            }
+        }
+
         mCurrentBatteryLevel = level;
         if (mDischargePlugLevel < 0) {
             mDischargePlugLevel = level;
@@ -13079,7 +13285,7 @@
                 final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
                 mDischargeCounter.addCountLocked(chargeDiff);
                 mDischargeScreenOffCounter.addCountLocked(chargeDiff);
-                if (isScreenDoze(mScreenState)) {
+                if (Display.isDozeState(mScreenState)) {
                     mDischargeScreenDozeCounter.addCountLocked(chargeDiff);
                 }
                 if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) {
@@ -13130,7 +13336,7 @@
                     final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
                     mDischargeCounter.addCountLocked(chargeDiff);
                     mDischargeScreenOffCounter.addCountLocked(chargeDiff);
-                    if (isScreenDoze(mScreenState)) {
+                    if (Display.isDozeState(mScreenState)) {
                         mDischargeScreenDozeCounter.addCountLocked(chargeDiff);
                     }
                     if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) {
@@ -13584,7 +13790,7 @@
     public int getDischargeAmountScreenOn() {
         synchronized(this) {
             int val = mDischargeAmountScreenOn;
-            if (mOnBattery && isScreenOn(mScreenState)
+            if (mOnBattery && Display.isOnState(mScreenState)
                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
             }
@@ -13596,7 +13802,7 @@
     public int getDischargeAmountScreenOnSinceCharge() {
         synchronized(this) {
             int val = mDischargeAmountScreenOnSinceCharge;
-            if (mOnBattery && isScreenOn(mScreenState)
+            if (mOnBattery && Display.isOnState(mScreenState)
                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
             }
@@ -13609,7 +13815,7 @@
     public int getDischargeAmountScreenOff() {
         synchronized(this) {
             int val = mDischargeAmountScreenOff;
-            if (mOnBattery && isScreenOff(mScreenState)
+            if (mOnBattery && Display.isOffState(mScreenState)
                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
             }
@@ -13622,7 +13828,7 @@
     public int getDischargeAmountScreenOffSinceCharge() {
         synchronized(this) {
             int val = mDischargeAmountScreenOffSinceCharge;
-            if (mOnBattery && isScreenOff(mScreenState)
+            if (mOnBattery && Display.isOffState(mScreenState)
                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
             }
@@ -13635,7 +13841,7 @@
     public int getDischargeAmountScreenDoze() {
         synchronized(this) {
             int val = mDischargeAmountScreenDoze;
-            if (mOnBattery && isScreenDoze(mScreenState)
+            if (mOnBattery && Display.isDozeState(mScreenState)
                     && mDischargeCurrentLevel < mDischargeScreenDozeUnplugLevel) {
                 val += mDischargeScreenDozeUnplugLevel-mDischargeCurrentLevel;
             }
@@ -13647,7 +13853,7 @@
     public int getDischargeAmountScreenDozeSinceCharge() {
         synchronized(this) {
             int val = mDischargeAmountScreenDozeSinceCharge;
-            if (mOnBattery && isScreenDoze(mScreenState)
+            if (mOnBattery && Display.isDozeState(mScreenState)
                     && mDischargeCurrentLevel < mDischargeScreenDozeUnplugLevel) {
                 val += mDischargeScreenDozeUnplugLevel-mDischargeCurrentLevel;
             }
@@ -14129,6 +14335,19 @@
         }
     }
 
+    /**
+     * Dump measured energy stats
+     */
+    @GuardedBy("this")
+    public void dumpMeasuredEnergyStatsLocked(PrintWriter pw) {
+        if (mBatteryMeasuredEnergyStats == null) return;
+        final IndentingPrintWriter iPw = new IndentingPrintWriter(pw, "    ");
+        iPw.println("On battery measured energy stats:");
+        iPw.increaseIndent();
+        mBatteryMeasuredEnergyStats.dump(iPw);
+        iPw.decreaseIndent();
+    }
+
     final ReentrantLock mWriteLock = new ReentrantLock();
 
     public void writeAsyncLocked() {
@@ -14504,6 +14723,8 @@
         mNextMaxDailyDeadlineMs = in.readLong();
         mBatteryTimeToFullSeconds = in.readLong();
 
+        MeasuredEnergyStats.readSummaryFromParcel(mBatteryMeasuredEnergyStats, in);
+
         mStartCount++;
 
         mScreenState = Display.STATE_UNKNOWN;
@@ -14997,6 +15218,8 @@
         out.writeLong(mNextMaxDailyDeadlineMs);
         out.writeLong(mBatteryTimeToFullSeconds);
 
+        MeasuredEnergyStats.writeSummaryToParcel(mBatteryMeasuredEnergyStats, out);
+
         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -15581,6 +15804,10 @@
         mLastWriteTimeMs = in.readLong();
         mBatteryTimeToFullSeconds = in.readLong();
 
+        if (in.readInt() != 0) {
+            mBatteryMeasuredEnergyStats = new MeasuredEnergyStats(in);
+        }
+
         mRpmStats.clear();
         int NRPMS = in.readInt();
         for (int irpm = 0; irpm < NRPMS; irpm++) {
@@ -15783,6 +16010,13 @@
         out.writeLong(mLastWriteTimeMs);
         out.writeLong(mBatteryTimeToFullSeconds);
 
+        if (mBatteryMeasuredEnergyStats != null) {
+            out.writeInt(1);
+            mBatteryMeasuredEnergyStats.writeToParcel(out);
+        } else {
+            out.writeInt(0);
+        }
+
         out.writeInt(mRpmStats.size());
         for (Map.Entry<String, SamplingTimer> ent : mRpmStats.entrySet()) {
             SamplingTimer rpmt = ent.getValue();
@@ -15950,6 +16184,48 @@
     }
 
     public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
+        if (ENABLE_FOREGROUND_STATS_COLLECTION) {
+            long actualCharge = -1;
+            long actualEnergy = -1;
+            try {
+                IBatteryPropertiesRegistrar registrar =
+                        IBatteryPropertiesRegistrar.Stub.asInterface(
+                                ServiceManager.getService("batteryproperties"));
+                if (registrar != null) {
+                    BatteryProperty prop = new BatteryProperty();
+                    if (registrar.getProperty(
+                                BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER, prop) == 0) {
+                        actualCharge = prop.getLong();
+                    }
+                    prop = new BatteryProperty();
+                    if (registrar.getProperty(
+                                BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER, prop) == 0) {
+                        actualEnergy = prop.getLong();
+                    }
+                }
+            } catch (RemoteException e) {
+                // Ignore.
+            }
+            pw.printf("ActualCharge (uAh): %d\n", (int) actualCharge);
+            pw.printf("ActualEnergy (nWh): %d\n", actualEnergy);
+            pw.printf("mBatteryCharge (uAh): %d\n", mBatteryCharge);
+            pw.printf("mBatteryVolts (mV): %d\n", mBatteryVolt);
+            pw.printf("est energy (nWh): %d\n", mBatteryVolt * (long) mBatteryCharge);
+            pw.printf("mEstimatedBatteryCapacity (mAh): %d\n", mEstimatedBatteryCapacity);
+            pw.printf("mMinLearnedBatteryCapacity (uAh): %d\n", mMinLearnedBatteryCapacity);
+            pw.printf("mMaxLearnedBatteryCapacity (uAh): %d\n", mMaxLearnedBatteryCapacity);
+            pw.printf("est. capacity: %f\n",
+                    (float) actualCharge / (mEstimatedBatteryCapacity * 1000));
+            pw.printf("mCurrentBatteryLevel: %d\n", mCurrentBatteryLevel);
+            pw.println("Total Power per app:");
+            mUidToPower.entrySet().forEach(e ->
+                    pw.printf("Uid: %d, Total watts (nW): %f\n",
+                            e.getKey(), e.getValue().computePower()));
+            pw.println("Total Power per app after first 2 minutes initial launch:");
+            mUidToPower.entrySet().forEach(e ->
+                    pw.printf("Uid: %d, Total watts (nW): %f\n",
+                            e.getKey(), e.getValue().computeFilteredPower()));
+        }
         if (DEBUG) {
             pw.println("mOnBatteryTimeBase:");
             mOnBatteryTimeBase.dump(pw, "  ");
@@ -16036,5 +16312,8 @@
 
         pw.println();
         dumpConstantsLocked(pw);
+
+        pw.println();
+        dumpMeasuredEnergyStatsLocked(pw);
     }
 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 1fcc6b0..94e21e5 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -391,16 +391,19 @@
         SharedLibraryInfo hidlBase = new SharedLibraryInfo(
                 "/system/framework/android.hidl.base-V1.0-java.jar", null /*packageName*/,
                 null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
-                null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
+                null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/,
+                false /*isNative*/);
         SharedLibraryInfo hidlManager = new SharedLibraryInfo(
                 "/system/framework/android.hidl.manager-V1.0-java.jar", null /*packageName*/,
                 null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
-                null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
+                null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/,
+                false /*isNative*/);
 
         SharedLibraryInfo androidTestBase = new SharedLibraryInfo(
                 "/system/framework/android.test.base.jar", null /*packageName*/,
                 null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
-                null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
+                null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/,
+                false /*isNative*/);
 
         ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders(
                 new SharedLibraryInfo[]{
@@ -625,8 +628,11 @@
 
     /**
      * Creates a PathClassLoader for the given class path that is associated with a shared
-     * namespace, i.e., this classloader can access platform-private native libraries. The
-     * classloader will use java.library.path as the native library path.
+     * namespace, i.e., this classloader can access platform-private native libraries.
+     *
+     * The classloader will add java.library.path to the native library path for the classloader
+     * namespace. Since it includes platform locations like /system/lib, this is only appropriate
+     * for platform code that don't need linker namespace isolation (as opposed to APEXes and apps).
      */
     static ClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
         String libraryPath = System.getProperty("java.library.path");
diff --git a/core/java/com/android/internal/power/MeasuredEnergyArray.java b/core/java/com/android/internal/power/MeasuredEnergyArray.java
new file mode 100644
index 0000000..1f6dc26
--- /dev/null
+++ b/core/java/com/android/internal/power/MeasuredEnergyArray.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.power;
+
+
+import android.annotation.IntDef;
+
+import com.android.internal.os.RailStats;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface to provide subsystem energy data.
+ * TODO: replace this and {@link RailStats} once b/173077356 is done
+ */
+public interface MeasuredEnergyArray {
+    int SUBSYSTEM_UNKNOWN = -1;
+    int SUBSYSTEM_DISPLAY = 0;
+    int NUMBER_SUBSYSTEMS = 1;
+    String[] SUBSYSTEM_NAMES = {"display"};
+
+
+    @IntDef(prefix = { "SUBSYSTEM_" }, value = {
+            SUBSYSTEM_UNKNOWN,
+            SUBSYSTEM_DISPLAY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface MeasuredEnergySubsystem {}
+
+    /**
+     * Get the subsystem at an index in array.
+     *
+     * @param index into the array.
+     * @return subsystem.
+     */
+    @MeasuredEnergySubsystem
+    int getSubsystem(int index);
+
+    /**
+     * Get the energy (in microjoules) consumed since boot of the subsystem at an index.
+     *
+     * @param index into the array.
+     * @return energy (in microjoules) consumed since boot.
+     */
+    long getEnergy(int index);
+
+    /**
+     * Return number of subsystems in the array.
+     */
+    int size();
+}
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
new file mode 100644
index 0000000..7b6e079
--- /dev/null
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.power;
+
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.view.Display;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.power.MeasuredEnergyArray.MeasuredEnergySubsystem;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * MeasuredEnergyStats adds up the measured energy usage of various subsystems
+ */
+@VisibleForTesting
+public class MeasuredEnergyStats {
+    private static final long UNAVAILABLE = -1;
+    private static final long RESET = -2;
+
+    public static final int ENERGY_BUCKET_UNKNOWN = -1;
+    public static final int ENERGY_BUCKET_SCREEN_ON = 0;
+    public static final int ENERGY_BUCKET_SCREEN_DOZE = 1;
+    public static final int ENERGY_BUCKET_SCREEN_OTHER = 2;
+    public static final int NUMBER_ENERGY_BUCKETS = 3;
+    private static final String[] ENERGY_BUCKET_NAMES =
+            {"screen-on", "screen-doze", "screen-other"};
+
+    @IntDef(prefix = {"ENERGY_BUCKET_"}, value = {
+            ENERGY_BUCKET_UNKNOWN,
+            ENERGY_BUCKET_SCREEN_ON,
+            ENERGY_BUCKET_SCREEN_DOZE,
+            ENERGY_BUCKET_SCREEN_OTHER,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EnergyBucket {
+    }
+
+    /**
+     * Energy snapshots from the last time each {@link MeasuredEnergySubsystem} was updated.
+     * An energy snapshot will be set to {@link #UNAVAILABLE} if the subsystem has never been
+     * updated.
+     * An energy snapshot will be set to {@link #RESET} on a reset. A subsystems energy will
+     * need to be updated at least twice to start accumulating energy again.
+     */
+    private final long[] mMeasuredEnergySnapshots =
+            new long[MeasuredEnergyArray.NUMBER_SUBSYSTEMS];
+
+    /**
+     * Total energy in microjoules since the last reset that an {@link EnergyBucket} has
+     * accumulated.
+     *
+     * Warning: Long array is used for access speed. If the number of supported subsystems
+     * becomes too large, consider using an alternate data structure.
+     */
+    private final long[] mAccumulatedEnergiesMicroJoules = new long[NUMBER_ENERGY_BUCKETS];
+
+    /**
+     * Last known screen state.
+     */
+    private int mLastScreenState;
+
+    public MeasuredEnergyStats(MeasuredEnergyArray energyArray, int screenState) {
+        Arrays.fill(mMeasuredEnergySnapshots, UNAVAILABLE);
+
+        update(energyArray, screenState, false);
+    }
+
+    public MeasuredEnergyStats(Parcel in) {
+        in.readLongArray(mAccumulatedEnergiesMicroJoules);
+    }
+
+    /**
+     * Constructor for creating a temp MeasuredEnergyStats
+     * See {@link #readSummaryFromParcel(MeasuredEnergyStats, Parcel)}
+     */
+    private MeasuredEnergyStats() {
+        Arrays.fill(mMeasuredEnergySnapshots, UNAVAILABLE);
+    }
+
+    /** Write to parcel */
+    public void writeToParcel(Parcel out) {
+        out.writeLongArray(mAccumulatedEnergiesMicroJoules);
+    }
+
+    /**
+     * Read from summary parcel.
+     * Note: Measured subsystem availability may be different from when the summary parcel was
+     * written.
+     */
+    private void readSummaryFromParcel(Parcel in) {
+        final int size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            final int bucket = in.readInt();
+            final long energyUJ = in.readLong();
+
+            final int subsystem = getSubsystem(bucket);
+            // Only accept the summary energy if subsystem is currently available
+            if (subsystem != MeasuredEnergyArray.SUBSYSTEM_UNKNOWN
+                    && mMeasuredEnergySnapshots[subsystem] != UNAVAILABLE) {
+                mAccumulatedEnergiesMicroJoules[bucket] = energyUJ;
+            }
+        }
+    }
+
+    /**
+     * Write to summary parcel.
+     * Note: Measured subsystem availability may be different when the summary parcel is read.
+     * Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} must be updated if summary
+     *       parceling changes.
+     */
+    private void writeSummaryToParcel(Parcel out) {
+        final int sizePos = out.dataPosition();
+        out.writeInt(0);
+        int size = 0;
+        // Write only the buckets with reported energy
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            final int subsystem = getSubsystem(i);
+            if (mMeasuredEnergySnapshots[subsystem] == UNAVAILABLE) continue;
+
+            out.writeInt(i);
+            out.writeLong(mAccumulatedEnergiesMicroJoules[i]);
+            size++;
+        }
+        final int currPos = out.dataPosition();
+        out.setDataPosition(sizePos);
+        out.writeInt(size);
+        out.setDataPosition(currPos);
+    }
+
+    /**
+     * Update with the latest measured energies and device state.
+     *
+     * @param energyArray measured energy array for some subsystems.
+     * @param screenState screen state to attribute disaply energy to after this update.
+     * @param accumulate whether or not to accumulate the latest energy
+     */
+    public void update(MeasuredEnergyArray energyArray, int screenState, boolean accumulate) {
+        final int size = energyArray.size();
+        if (!accumulate) {
+            for (int i = 0; i < size; i++) {
+                final int subsystem = energyArray.getSubsystem(i);
+                mMeasuredEnergySnapshots[subsystem] = energyArray.getEnergy(i);
+            }
+        } else {
+            for (int i = 0; i < size; i++) {
+                final int subsystem = energyArray.getSubsystem(i);
+                final long newEnergyUJ = energyArray.getEnergy(i);
+                final long oldEnergyUJ = mMeasuredEnergySnapshots[subsystem];
+                mMeasuredEnergySnapshots[subsystem] = newEnergyUJ;
+
+                // This is the first valid energy, skip accumulating the delta
+                if (oldEnergyUJ < 0) continue;
+                final long deltaUJ = newEnergyUJ - oldEnergyUJ;
+
+                final int bucket = getEnergyBucket(subsystem, mLastScreenState);
+                mAccumulatedEnergiesMicroJoules[bucket] += deltaUJ;
+            }
+        }
+        mLastScreenState = screenState;
+    }
+
+    /**
+     * Map {@link MeasuredEnergySubsystem} and device state to an {@link EnergyBucket}.
+     * Keep in sync with {@link #getSubsystem}
+     */
+    @EnergyBucket
+    private int getEnergyBucket(@MeasuredEnergySubsystem int subsystem, int screenState) {
+        switch (subsystem) {
+            case MeasuredEnergyArray.SUBSYSTEM_DISPLAY:
+                if (Display.isOnState(screenState)) {
+                    return ENERGY_BUCKET_SCREEN_ON;
+                } else if (Display.isDozeState(screenState)) {
+                    return ENERGY_BUCKET_SCREEN_DOZE;
+                } else {
+                    return ENERGY_BUCKET_SCREEN_OTHER;
+                }
+            default:
+                return ENERGY_BUCKET_UNKNOWN;
+        }
+    }
+
+    /**
+     * Map {@link EnergyBucket} to a {@link MeasuredEnergySubsystem}.
+     * Keep in sync with {@link #getEnergyBucket}
+     */
+    @MeasuredEnergySubsystem
+    private int getSubsystem(@EnergyBucket int bucket) {
+        switch (bucket) {
+            case ENERGY_BUCKET_SCREEN_ON: //fallthrough
+            case ENERGY_BUCKET_SCREEN_DOZE: //fallthrough
+            case ENERGY_BUCKET_SCREEN_OTHER:
+                return MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
+            default:
+                return MeasuredEnergyArray.SUBSYSTEM_UNKNOWN;
+        }
+    }
+
+    /**
+     * Check if a subsystem's measured energy is available.
+     * @param subsystem which subsystem.
+     * @return true if subsystem is avaiable.
+     */
+    public boolean hasSubsystem(@MeasuredEnergySubsystem int subsystem) {
+        return mMeasuredEnergySnapshots[subsystem] != UNAVAILABLE;
+    }
+
+    /**
+     * Return accumulated energy (in microjoules) since last reset.
+     */
+    public long getAccumulatedBucketEnergy(@EnergyBucket int bucket) {
+        return mAccumulatedEnergiesMicroJoules[bucket];
+    }
+
+    /**
+     * Populate a MeasuredEnergyStats from a parcel. If the stats is null, consume and
+     * ignore the parcelled data.
+     */
+    public static void readSummaryFromParcel(@Nullable MeasuredEnergyStats stats, Parcel in) {
+        // Check if any MeasuredEnergyStats exists on the parcel
+        if (in.readInt() == 0) return;
+
+        // If stats is null, create a placeholder MeasuredEnergyStats to consume the parcel data
+        final MeasuredEnergyStats mes = stats != null ? stats : new MeasuredEnergyStats();
+        mes.readSummaryFromParcel(in);
+    }
+
+    /**
+     * Write a MeasuredEnergyStats to a parcel. If the stats is null, just write a 0.
+     */
+    public static void writeSummaryToParcel(@Nullable MeasuredEnergyStats stats,
+            Parcel dest) {
+        if (stats == null) {
+            dest.writeInt(0);
+            return;
+        }
+        dest.writeInt(1);
+        stats.writeSummaryToParcel(dest);
+    }
+
+    /**
+     * Reset accumulated energy.
+     */
+    public void reset() {
+        for (int i = 0; i < MeasuredEnergyArray.NUMBER_SUBSYSTEMS; i++) {
+            // Leave subsystems marked as unavailable alone.
+            if (mMeasuredEnergySnapshots[i] == UNAVAILABLE) continue;
+            mMeasuredEnergySnapshots[i] = RESET;
+        }
+        Arrays.fill(mAccumulatedEnergiesMicroJoules, 0);
+    }
+
+    /**
+     * Dump debug data.
+     */
+    public void dump(PrintWriter pw) {
+        pw.println("Measured energy snapshot (microjoules):");
+        pw.print("   ");
+        for (int i = 0; i < MeasuredEnergyArray.NUMBER_SUBSYSTEMS; i++) {
+            final long energyUJ = mMeasuredEnergySnapshots[i];
+            if (energyUJ == UNAVAILABLE) continue;
+            pw.print(MeasuredEnergyArray.SUBSYSTEM_NAMES[i]);
+            pw.print(" : ");
+            if (energyUJ == RESET) {
+                pw.print("reset");
+            } else {
+                pw.print(energyUJ);
+            }
+            if (i != MeasuredEnergyArray.NUMBER_SUBSYSTEMS - 1) {
+                pw.print(", ");
+            }
+        }
+        pw.println();
+
+        pw.println("Accumulated energy since last reset (microjoules):");
+        pw.print("   ");
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            pw.print(ENERGY_BUCKET_NAMES[i]);
+            pw.print(" : ");
+            pw.print(mAccumulatedEnergiesMicroJoules[i]);
+            if (i != NUMBER_ENERGY_BUCKETS - 1) {
+                pw.print(", ");
+            }
+        }
+        pw.println();
+    }
+}
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
index 94e07a8..929c9e8 100644
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ b/core/java/com/android/internal/util/FastXmlSerializer.java
@@ -367,8 +367,11 @@
 
     public void startDocument(String encoding, Boolean standalone) throws IOException,
             IllegalArgumentException, IllegalStateException {
-        append("<?xml version='1.0' encoding='utf-8' standalone='"
-                + (standalone ? "yes" : "no") + "' ?>\n");
+        append("<?xml version='1.0' encoding='utf-8'");
+        if (standalone != null) {
+            append(" standalone='" + (standalone ? "yes" : "no") + "'");
+        }
+        append(" ?>\n");
         mLineStart = true;
     }
 
diff --git a/core/java/com/android/internal/util/function/pooled/OWNERS b/core/java/com/android/internal/util/function/pooled/OWNERS
new file mode 100644
index 0000000..da723b3
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 33ebe43..4deb40a 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -25,6 +25,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.inputmethod.CompletionInfo;
@@ -111,6 +112,12 @@
         }
     }
 
+    protected Looper getLooper() {
+        synchronized (mMainLooper) {
+            return mMainLooper;
+        }
+    }
+
     protected boolean isFinished() {
         synchronized (mLock) {
             return mFinished;
@@ -259,61 +266,80 @@
     void executeMessage(Message msg) {
         switch (msg.what) {
             case DO_GET_TEXT_AFTER_CURSOR: {
-                final ICharSequenceResultCallback callback = (ICharSequenceResultCallback) msg.obj;
-                final InputConnection ic = getInputConnection();
-                final CharSequence result;
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
-                    result = null;
-                } else {
-                    result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
-                }
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
                 try {
-                    callback.onResult(result);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
+                    final ICharSequenceResultCallback callback =
+                            (ICharSequenceResultCallback) msg.obj;
+                    final InputConnection ic = getInputConnection();
+                    final CharSequence result;
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
+                        result = null;
+                    } else {
+                        result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
+                    }
+                    try {
+                        callback.onResult(result);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
                             + " result=" + result, e);
+                    }
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
                 return;
             }
             case DO_GET_TEXT_BEFORE_CURSOR: {
-                final ICharSequenceResultCallback callback = (ICharSequenceResultCallback) msg.obj;
-                final InputConnection ic = getInputConnection();
-                final CharSequence result;
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
-                    result = null;
-                } else {
-                    result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
-                }
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
                 try {
-                    callback.onResult(result);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
+                    final ICharSequenceResultCallback callback =
+                            (ICharSequenceResultCallback) msg.obj;
+                    final InputConnection ic = getInputConnection();
+                    final CharSequence result;
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
+                        result = null;
+                    } else {
+                        result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
+                    }
+                    try {
+                        callback.onResult(result);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
                             + " result=" + result, e);
+                    }
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
                 return;
             }
             case DO_GET_SELECTED_TEXT: {
-                final ICharSequenceResultCallback callback = (ICharSequenceResultCallback) msg.obj;
-                final InputConnection ic = getInputConnection();
-                final CharSequence result;
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "getSelectedText on inactive InputConnection");
-                    result = null;
-                } else {
-                    result = ic.getSelectedText(msg.arg1);
-                }
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
                 try {
-                    callback.onResult(result);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to return the result to getSelectedText()."
-                            + " result=" + result, e);
+                    final ICharSequenceResultCallback callback =
+                            (ICharSequenceResultCallback) msg.obj;
+                    final InputConnection ic = getInputConnection();
+                    final CharSequence result;
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "getSelectedText on inactive InputConnection");
+                        result = null;
+                    } else {
+                        result = ic.getSelectedText(msg.arg1);
+                    }
+                    try {
+                        callback.onResult(result);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to return the result to getSelectedText()."
+                                + " result=" + result, e);
+                    }
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
                 return;
             }
             case DO_GET_SURROUNDING_TEXT: {
                 final SomeArgs args = (SomeArgs) msg.obj;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
                 try {
                     int beforeLength = (int) args.arg1;
                     int afterLength  = (int) args.arg2;
@@ -335,30 +361,37 @@
                                 + " result=" + result, e);
                     }
                 } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                     args.recycle();
                 }
                 return;
             }
             case DO_GET_CURSOR_CAPS_MODE: {
-                final IIntResultCallback callback = (IIntResultCallback) msg.obj;
-                final InputConnection ic = getInputConnection();
-                final int result;
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
-                    result = 0;
-                } else {
-                    result = ic.getCursorCapsMode(msg.arg1);
-                }
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
                 try {
-                    callback.onResult(result);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
+                    final IIntResultCallback callback = (IIntResultCallback) msg.obj;
+                    final InputConnection ic = getInputConnection();
+                    final int result;
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
+                        result = 0;
+                    } else {
+                        result = ic.getCursorCapsMode(msg.arg1);
+                    }
+                    try {
+                        callback.onResult(result);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
                             + " result=" + result, e);
+                    }
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
                 return;
             }
             case DO_GET_EXTRACTED_TEXT: {
                 final SomeArgs args = (SomeArgs) msg.obj;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
                 try {
                     final ExtractedTextRequest request = (ExtractedTextRequest) args.arg1;
                     final IExtractedTextResultCallback callback =
@@ -378,159 +411,237 @@
                                 + " result=" + result, e);
                     }
                 } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                     args.recycle();
                 }
                 return;
             }
             case DO_COMMIT_TEXT: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "commitText on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "commitText on inactive InputConnection");
+                        return;
+                    }
+                    ic.commitText((CharSequence) msg.obj, msg.arg1);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.commitText((CharSequence)msg.obj, msg.arg1);
                 return;
             }
             case DO_SET_SELECTION: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "setSelection on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "setSelection on inactive InputConnection");
+                        return;
+                    }
+                    ic.setSelection(msg.arg1, msg.arg2);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.setSelection(msg.arg1, msg.arg2);
                 return;
             }
             case DO_PERFORM_EDITOR_ACTION: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "performEditorAction on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "performEditorAction on inactive InputConnection");
+                        return;
+                    }
+                    ic.performEditorAction(msg.arg1);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.performEditorAction(msg.arg1);
                 return;
             }
             case DO_PERFORM_CONTEXT_MENU_ACTION: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "performContextMenuAction on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "performContextMenuAction on inactive InputConnection");
+                        return;
+                    }
+                    ic.performContextMenuAction(msg.arg1);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.performContextMenuAction(msg.arg1);
                 return;
             }
             case DO_COMMIT_COMPLETION: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "commitCompletion on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "commitCompletion on inactive InputConnection");
+                        return;
+                    }
+                    ic.commitCompletion((CompletionInfo) msg.obj);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.commitCompletion((CompletionInfo)msg.obj);
                 return;
             }
             case DO_COMMIT_CORRECTION: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "commitCorrection on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "commitCorrection on inactive InputConnection");
+                        return;
+                    }
+                    ic.commitCorrection((CorrectionInfo) msg.obj);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.commitCorrection((CorrectionInfo)msg.obj);
                 return;
             }
             case DO_SET_COMPOSING_TEXT: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "setComposingText on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "setComposingText on inactive InputConnection");
+                        return;
+                    }
+                    ic.setComposingText((CharSequence) msg.obj, msg.arg1);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.setComposingText((CharSequence)msg.obj, msg.arg1);
                 return;
             }
             case DO_SET_COMPOSING_REGION: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "setComposingRegion on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "setComposingRegion on inactive InputConnection");
+                        return;
+                    }
+                    ic.setComposingRegion(msg.arg1, msg.arg2);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.setComposingRegion(msg.arg1, msg.arg2);
                 return;
             }
             case DO_FINISH_COMPOSING_TEXT: {
-                if (isFinished()) {
-                    // In this case, #finishComposingText() is guaranteed to be called already.
-                    // There should be no negative impact if we ignore this call silently.
-                    if (DEBUG) {
-                        Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
+                try {
+                    if (isFinished()) {
+                        // In this case, #finishComposingText() is guaranteed to be called already.
+                        // There should be no negative impact if we ignore this call silently.
+                        if (DEBUG) {
+                            Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
+                        }
+                        return;
                     }
-                    return;
+                    InputConnection ic = getInputConnection();
+                    // Note we do NOT check isActive() here, because this is safe
+                    // for an IME to call at any time, and we need to allow it
+                    // through to clean up our state after the IME has switched to
+                    // another client.
+                    if (ic == null) {
+                        Log.w(TAG, "finishComposingText on inactive InputConnection");
+                        return;
+                    }
+                    ic.finishComposingText();
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                InputConnection ic = getInputConnection();
-                // Note we do NOT check isActive() here, because this is safe
-                // for an IME to call at any time, and we need to allow it
-                // through to clean up our state after the IME has switched to
-                // another client.
-                if (ic == null) {
-                    Log.w(TAG, "finishComposingText on inactive InputConnection");
-                    return;
-                }
-                ic.finishComposingText();
                 return;
             }
             case DO_SEND_KEY_EVENT: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "sendKeyEvent on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "sendKeyEvent on inactive InputConnection");
+                        return;
+                    }
+                    ic.sendKeyEvent((KeyEvent) msg.obj);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.sendKeyEvent((KeyEvent)msg.obj);
                 return;
             }
             case DO_CLEAR_META_KEY_STATES: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
+                        return;
+                    }
+                    ic.clearMetaKeyStates(msg.arg1);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.clearMetaKeyStates(msg.arg1);
                 return;
             }
             case DO_DELETE_SURROUNDING_TEXT: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
+                        return;
+                    }
+                    ic.deleteSurroundingText(msg.arg1, msg.arg2);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.deleteSurroundingText(msg.arg1, msg.arg2);
                 return;
             }
             case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT,
+                        "InputConnection#deleteSurroundingTextInCodePoints");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
+                        return;
+                    }
+                    ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
                 return;
             }
             case DO_BEGIN_BATCH_EDIT: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "beginBatchEdit on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "beginBatchEdit on inactive InputConnection");
+                        return;
+                    }
+                    ic.beginBatchEdit();
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.beginBatchEdit();
                 return;
             }
             case DO_END_BATCH_EDIT: {
-                InputConnection ic = getInputConnection();
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "endBatchEdit on inactive InputConnection");
-                    return;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "endBatchEdit on inactive InputConnection");
+                        return;
+                    }
+                    ic.endBatchEdit();
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
-                ic.endBatchEdit();
                 return;
             }
             case DO_PERFORM_PRIVATE_COMMAND: {
                 final SomeArgs args = (SomeArgs) msg.obj;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
                 try {
                     final String action = (String) args.arg1;
                     final Bundle data = (Bundle) args.arg2;
@@ -541,25 +652,31 @@
                     }
                     ic.performPrivateCommand(action, data);
                 } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                     args.recycle();
                 }
                 return;
             }
             case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
-                final IIntResultCallback callback = (IIntResultCallback) msg.obj;
-                final InputConnection ic = getInputConnection();
-                final boolean result;
-                if (ic == null || !isActive()) {
-                    Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
-                    result = false;
-                } else {
-                    result = ic.requestCursorUpdates(msg.arg1);
-                }
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
                 try {
-                    callback.onResult(result ? 1 : 0);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
-                            + " result=" + result, e);
+                    final IIntResultCallback callback = (IIntResultCallback) msg.obj;
+                    final InputConnection ic = getInputConnection();
+                    final boolean result;
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
+                        result = false;
+                    } else {
+                        result = ic.requestCursorUpdates(msg.arg1);
+                    }
+                    try {
+                        callback.onResult(result ? 1 : 0);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
+                                + " result=" + result, e);
+                    }
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
                 return;
             }
@@ -571,6 +688,7 @@
                 if (isFinished()) {
                     return;
                 }
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
                 try {
                     InputConnection ic = getInputConnection();
                     // Note we do NOT check isActive() here, because this is safe
@@ -590,12 +708,14 @@
                         mInputConnection = null;
                         mFinished = true;
                     }
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                 }
                 return;
             }
             case DO_COMMIT_CONTENT: {
                 final int flags = msg.arg1;
                 SomeArgs args = (SomeArgs) msg.obj;
+                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
                 try {
                     final IIntResultCallback callback = (IIntResultCallback) args.arg3;
                     final InputConnection ic = getInputConnection();
@@ -620,6 +740,7 @@
                                 + " result=" + result, e);
                     }
                 } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
                     args.recycle();
                 }
                 return;
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 1145f51..ec9a0a2 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -25,7 +25,7 @@
 oneway interface IInputMethodClient {
     void onBindMethod(in InputBindResult res);
     void onUnbindMethod(int sequence, int unbindReason);
-    void setActive(boolean active, boolean fullscreen);
+    void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
     void scheduleStartInputIfNecessary(boolean fullscreen);
     void reportFullscreenMode(boolean fullscreen);
     void applyImeVisibility(boolean setVisible);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 844c56b..e78ed4e 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -24,6 +24,7 @@
 import com.android.internal.view.InputBindResult;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
+import com.android.internal.inputmethod.IInputBindResultResultCallback;
 
 /**
  * Public interface to the global input method manager, used by all client
@@ -48,14 +49,15 @@
     // If windowToken is null, this just does startInput().  Otherwise this reports that a window
     // has gained focus, and if 'attribute' is non-null then also does startInput.
     // @NonNull
-    InputBindResult startInputOrWindowGainedFocus(
+    void startInputOrWindowGainedFocus(
             /* @StartInputReason */ int startInputReason,
             in IInputMethodClient client, in IBinder windowToken,
             /* @StartInputFlags */ int startInputFlags,
             /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
             int windowFlags, in EditorInfo attribute, IInputContext inputContext,
             /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags,
-            int unverifiedTargetSdkVersion);
+            int unverifiedTargetSdkVersion,
+            in IInputBindResultResultCallback inputBindResult);
 
     void showInputMethodPickerFromClient(in IInputMethodClient client,
             int auxiliarySubtypeMode);
@@ -79,4 +81,9 @@
     void removeImeSurfaceFromWindow(in IBinder windowToken);
     void startProtoDump(in byte[] protoDump, int source, String where);
     boolean isImeTraceEnabled();
+
+    // Starts an ime trace.
+    void startImeTrace();
+    // Stops an ime trace.
+    void stopImeTrace();
 }
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 0319e36..c6afd78 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -52,4 +52,6 @@
     void notifyImeHidden();
 
     void removeImeSurface();
+
+    void finishInput();
 }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index ec4fe17..8c763a6 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -24,7 +24,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
@@ -41,7 +40,6 @@
 import com.android.internal.inputmethod.ResultCallbacks;
 
 import java.lang.ref.WeakReference;
-import java.util.concurrent.TimeUnit;
 
 public class InputConnectionWrapper implements InputConnection {
     private static final String TAG = "InputConnectionWrapper";
@@ -73,43 +71,6 @@
         mCancellationGroup = cancellationGroup;
     }
 
-    @AnyThread
-    private static void logInternal(@Nullable String methodName, boolean timedOut,
-            @Nullable Object defaultValue) {
-        if (timedOut) {
-            Log.w(TAG, methodName + " didn't respond in " + MAX_WAIT_TIME_MILLIS + " msec."
-                    + " Returning default: " + defaultValue);
-        } else {
-            Log.w(TAG, methodName + " was canceled before complete. Returning default: "
-                    + defaultValue);
-        }
-    }
-
-    @AnyThread
-    private static int getResultOrZero(@NonNull Completable.Int value, @NonNull String methodName,
-            @Nullable CancellationGroup cancellationGroup) {
-        final boolean timedOut =
-                value.await(MAX_WAIT_TIME_MILLIS,  TimeUnit.MILLISECONDS, cancellationGroup);
-        if (value.hasValue()) {
-            return value.getValue();
-        }
-        logInternal(methodName, timedOut, 0);
-        return 0;
-    }
-
-    @AnyThread
-    @Nullable
-    private static <T> T getResultOrNull(@NonNull Completable.Values<T> value,
-            @NonNull String methodName, @Nullable CancellationGroup cancellationGroup) {
-        final boolean timedOut =
-                value.await(MAX_WAIT_TIME_MILLIS,  TimeUnit.MILLISECONDS, cancellationGroup);
-        if (value.hasValue()) {
-            return value.getValue();
-        }
-        logInternal(methodName, timedOut, null);
-        return null;
-    }
-
     /**
      * See {@link InputConnection#getTextAfterCursor(int, int)}.
      */
@@ -126,7 +87,8 @@
         } catch (RemoteException e) {
             return null;
         }
-        return getResultOrNull(value, "getTextAfterCursor()", mCancellationGroup);
+        return Completable.getResultOrNull(
+                value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
     /**
@@ -145,7 +107,8 @@
         } catch (RemoteException e) {
             return null;
         }
-        return getResultOrNull(value, "getTextBeforeCursor()", mCancellationGroup);
+        return Completable.getResultOrNull(
+                value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
     @AnyThread
@@ -164,7 +127,8 @@
         } catch (RemoteException e) {
             return null;
         }
-        return getResultOrNull(value, "getSelectedText()", mCancellationGroup);
+        return Completable.getResultOrNull(
+                value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
     /**
@@ -197,7 +161,8 @@
         } catch (RemoteException e) {
             return null;
         }
-        return getResultOrNull(value, "getSurroundingText()", mCancellationGroup);
+        return Completable.getResultOrNull(
+                value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
     @AnyThread
@@ -212,7 +177,8 @@
         } catch (RemoteException e) {
             return 0;
         }
-        return getResultOrZero(value, "getCursorCapsMode()", mCancellationGroup);
+        return Completable.getResultOrZero(
+                value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
     @AnyThread
@@ -227,7 +193,8 @@
         } catch (RemoteException e) {
             return null;
         }
-        return getResultOrNull(value, "getExtractedText()", mCancellationGroup);
+        return Completable.getResultOrNull(
+                value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
     }
 
     @AnyThread
@@ -438,7 +405,8 @@
         } catch (RemoteException e) {
             return false;
         }
-        return getResultOrZero(value, "requestUpdateCursorAnchorInfo()", mCancellationGroup) != 0;
+        return Completable.getResultOrZero(value, TAG, "requestUpdateCursorAnchorInfo()",
+                mCancellationGroup, MAX_WAIT_TIME_MILLIS) != 0;
     }
 
     @AnyThread
@@ -478,7 +446,8 @@
         } catch (RemoteException e) {
             return false;
         }
-        return getResultOrZero(value, "commitContent()", mCancellationGroup) != 0;
+        return Completable.getResultOrZero(
+                value, TAG, "commitContent()", mCancellationGroup, MAX_WAIT_TIME_MILLIS) != 0;
     }
 
     @AnyThread
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index ff3543c8..d30d662 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -16,21 +16,36 @@
 
 package com.android.internal.widget;
 
+import static android.view.inputmethod.InputConnectionProto.CURSOR_CAPS_MODE;
+import static android.view.inputmethod.InputConnectionProto.EDITABLE_TEXT;
+import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT;
+import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_END;
+import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_START;
+
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.text.Editable;
+import android.text.Selection;
 import android.text.method.KeyListener;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.DumpableInputConnection;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.widget.TextView;
 
-public class EditableInputConnection extends BaseInputConnection {
+/**
+ * Base class for an editable InputConnection instance. This is created by {@link TextView} or
+ * {@link EditText}.
+ */
+public class EditableInputConnection extends BaseInputConnection
+        implements DumpableInputConnection {
     private static final boolean DEBUG = false;
+    private static final boolean DUMP_TEXT = false;
     private static final String TAG = "EditableInputConnection";
 
     private final TextView mTextView;
@@ -222,4 +237,28 @@
         }
         return true;
     }
+
+    @Override
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        CharSequence editableText = mTextView.getText();
+        CharSequence selectedText = getSelectedText(0 /* flags */);
+        if (DUMP_TEXT) {
+            if (editableText != null) {
+                proto.write(EDITABLE_TEXT, editableText.toString());
+            }
+            if (selectedText != null) {
+                proto.write(SELECTED_TEXT, selectedText.toString());
+            }
+        }
+        final Editable content = getEditable();
+        if (content != null) {
+            int start = Selection.getSelectionStart(content);
+            int end = Selection.getSelectionEnd(content);
+            proto.write(SELECTED_TEXT_START, start);
+            proto.write(SELECTED_TEXT_END, end);
+        }
+        proto.write(CURSOR_CAPS_MODE, getCursorCapsMode(0));
+        proto.end(token);
+    }
 }
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 58817a8..514e0b8 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -61,12 +61,17 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -93,7 +98,6 @@
     private final Rect mPreviousContentRect = new Rect();
 
     private Menu mMenu;
-    private List<MenuItem> mShowingMenuItems = new ArrayList<>();
     private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
 
     private int mSuggestedWidth;
@@ -274,10 +278,11 @@
     private void doShow() {
         List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
         menuItems.sort(mMenuItemComparator);
-        if (!isCurrentlyShowing(menuItems) || mWidthChanged) {
+        if (mPopup.isLayoutRequired(menuItems) || mWidthChanged) {
             mPopup.dismiss();
             mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
-            mShowingMenuItems = menuItems;
+        } else {
+            mPopup.updateMenuItems(menuItems, mMenuItemClickListener);
         }
         if (!mPopup.isShowing()) {
             mPopup.show(mContentRect);
@@ -289,33 +294,10 @@
     }
 
     /**
-     * Returns true if this floating toolbar is currently showing the specified menu items.
-     */
-    private boolean isCurrentlyShowing(List<MenuItem> menuItems) {
-        if (mShowingMenuItems == null || menuItems.size() != mShowingMenuItems.size()) {
-            return false;
-        }
-
-        final int size = menuItems.size();
-        for (int i = 0; i < size; i++) {
-            final MenuItem menuItem = menuItems.get(i);
-            final MenuItem showingItem = mShowingMenuItems.get(i);
-            if (menuItem.getItemId() != showingItem.getItemId()
-                    || !TextUtils.equals(menuItem.getTitle(), showingItem.getTitle())
-                    || !Objects.equals(menuItem.getIcon(), showingItem.getIcon())
-                    || menuItem.getGroupId() != showingItem.getGroupId()) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
      * Returns the visible and enabled menu items in the specified menu.
      * This method is recursive.
      */
-    private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) {
+    private static List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) {
         List<MenuItem> menuItems = new ArrayList<>();
         for (int i = 0; (menu != null) && (i < menu.size()); i++) {
             MenuItem menuItem = menu.getItem(i);
@@ -427,17 +409,25 @@
         private Size mOverflowPanelSize;  // Should be null when there is no overflow.
         private Size mMainPanelSize;
 
-        /* Item click listeners */
+        /* Menu items and click listeners */
+        private final Map<MenuItemRepr, MenuItem> mMenuItems = new LinkedHashMap<>();
         private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
         private final View.OnClickListener mMenuItemButtonOnClickListener =
                 new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        if (v.getTag() instanceof MenuItem) {
-                            if (mOnMenuItemClickListener != null) {
-                                mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
-                            }
+                        if (mOnMenuItemClickListener == null) {
+                            return;
                         }
+                        final Object tag = v.getTag();
+                        if (!(tag instanceof MenuItemRepr)) {
+                            return;
+                        }
+                        final MenuItem menuItem = mMenuItems.get((MenuItemRepr) tag);
+                        if (menuItem == null) {
+                            return;
+                        }
+                        mOnMenuItemClickListener.onMenuItemClick(menuItem);
                     }
                 };
 
@@ -558,9 +548,9 @@
                 List<MenuItem> menuItems,
                 MenuItem.OnMenuItemClickListener menuItemClickListener,
                 int suggestedWidth) {
-            mOnMenuItemClickListener = menuItemClickListener;
             cancelOverflowAnimations();
             clearPanels();
+            updateMenuItems(menuItems, menuItemClickListener);
             menuItems = layoutMainPanelItems(menuItems, getAdjustedToolbarWidth(suggestedWidth));
             if (!menuItems.isEmpty()) {
                 // Add remaining items to the overflow.
@@ -570,6 +560,28 @@
         }
 
         /**
+         * Updates the popup's menu items without rebuilding the widget.
+         * Use in place of layoutMenuItems() when the popup's views need not be reconstructed.
+         *
+         * @see isLayoutRequired(List<MenuItem>)
+         */
+        public void updateMenuItems(
+                List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener) {
+            mMenuItems.clear();
+            for (MenuItem menuItem : menuItems) {
+                mMenuItems.put(MenuItemRepr.of(menuItem), menuItem);
+            }
+            mOnMenuItemClickListener = menuItemClickListener;
+        }
+
+        /**
+         * Returns true if this popup needs a relayout to properly render the specified menu items.
+         */
+        public boolean isLayoutRequired(List<MenuItem> menuItems) {
+            return !MenuItemRepr.reprEquals(menuItems, mMenuItems.values());
+        }
+
+        /**
          * Shows this popup at the specified coordinates.
          * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
          */
@@ -1374,7 +1386,7 @@
         }
 
         private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) {
-            menuItemButton.setTag(menuItem);
+            menuItemButton.setTag(MenuItemRepr.of(menuItem));
             menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
         }
 
@@ -1656,6 +1668,85 @@
     }
 
     /**
+     * Represents the identity of a MenuItem that is rendered in a FloatingToolbarPopup.
+     */
+    @VisibleForTesting
+    public static final class MenuItemRepr {
+
+        public final int itemId;
+        public final int groupId;
+        @Nullable public final String title;
+        @Nullable private final Drawable mIcon;
+
+        private MenuItemRepr(
+                int itemId, int groupId, @Nullable CharSequence title, @Nullable Drawable icon) {
+            this.itemId = itemId;
+            this.groupId = groupId;
+            this.title = (title == null) ? null : title.toString();
+            mIcon = icon;
+        }
+
+        /**
+         * Creates an instance of MenuItemRepr for the specified menu item.
+         */
+        public static MenuItemRepr of(MenuItem menuItem) {
+            return new MenuItemRepr(
+                    menuItem.getItemId(),
+                    menuItem.getGroupId(),
+                    menuItem.getTitle(),
+                    menuItem.getIcon());
+        }
+
+        /**
+         * Returns this object's hashcode.
+         */
+        @Override
+        public int hashCode() {
+            return Objects.hash(itemId, groupId, title, mIcon);
+        }
+
+        /**
+         * Returns true if this object is the same as the specified object.
+         */
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (!(o instanceof MenuItemRepr)) {
+                return false;
+            }
+            final MenuItemRepr other = (MenuItemRepr) o;
+            return itemId == other.itemId
+                    && groupId == other.groupId
+                    && TextUtils.equals(title, other.title)
+                    // Many Drawables (icons) do not implement equals(). Using equals() here instead
+                    // of reference comparisons in case a Drawable subclass implements equals().
+                    && Objects.equals(mIcon, other.mIcon);
+        }
+
+        /**
+         * Returns true if the two menu item collections are the same based on MenuItemRepr.
+         */
+        public static boolean reprEquals(
+                Collection<MenuItem> menuItems1, Collection<MenuItem> menuItems2) {
+            if (menuItems1.size() != menuItems2.size()) {
+                return false;
+            }
+
+            final Iterator<MenuItem> menuItems2Iter = menuItems2.iterator();
+            for (MenuItem menuItem1 : menuItems1) {
+                final MenuItem menuItem2 = menuItems2Iter.next();
+                if (!MenuItemRepr.of(menuItem1).equals(MenuItemRepr.of(menuItem2))) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    /**
      * Creates and returns a menu button for the specified menu item.
      */
     private static View createMenuItemButton(
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index b4e108f..3f205c78 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -16,69 +16,61 @@
 
 package com.android.internal.widget;
 
-import android.annotation.Nullable;
 import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.ImageDecoder;
+import android.graphics.drawable.AnimatedImageDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.util.Log;
+import android.util.Size;
 
 import java.io.IOException;
-import java.io.InputStream;
 
-/**
- * A class to extract Bitmaps from a MessagingStyle message.
- */
+/** A class to extract Drawables from a MessagingStyle/ConversationStyle message. */
 public class LocalImageResolver {
     private static final String TAG = LocalImageResolver.class.getSimpleName();
 
     private static final int MAX_SAFE_ICON_SIZE_PX = 480;
 
-    @Nullable
     public static Drawable resolveImage(Uri uri, Context context) throws IOException {
-        BitmapFactory.Options onlyBoundsOptions = getBoundsOptionsForImage(uri, context);
-        if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
-            return null;
-        }
-
-        int originalSize =
-                (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth)
-                        ? onlyBoundsOptions.outHeight
-                        : onlyBoundsOptions.outWidth;
-
-        double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX)
-                        ? (originalSize / MAX_SAFE_ICON_SIZE_PX)
-                        : 1.0;
-
-        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
-        bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
-        InputStream input = context.getContentResolver().openInputStream(uri);
-        Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
-        input.close();
-        return new BitmapDrawable(context.getResources(), bitmap);
+        final ImageDecoder.Source source =
+                ImageDecoder.createSource(context.getContentResolver(), uri);
+        final Drawable drawable =
+                ImageDecoder.decodeDrawable(source, LocalImageResolver::onHeaderDecoded);
+        return drawable;
     }
 
-    private static BitmapFactory.Options getBoundsOptionsForImage(Uri uri, Context context)
+    public static Drawable resolveImage(Uri uri, Context context, int maxWidth, int maxHeight)
             throws IOException {
-        BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
-        try (InputStream input = context.getContentResolver().openInputStream(uri)) {
-            if (input == null) {
-                throw new IllegalArgumentException();
+        final ImageDecoder.Source source =
+                ImageDecoder.createSource(context.getContentResolver(), uri);
+        return ImageDecoder.decodeDrawable(source, (decoder, info, unused) -> {
+            final Size size = info.getSize();
+            if (size.getWidth() > size.getHeight()) {
+                if (size.getWidth() > maxWidth) {
+                    final int targetHeight = size.getHeight() * maxWidth / size.getWidth();
+                    decoder.setTargetSize(maxWidth, targetHeight);
+                }
+            } else {
+                if (size.getHeight() > maxHeight) {
+                    final int targetWidth = size.getWidth() * maxHeight / size.getHeight();
+                    decoder.setTargetSize(targetWidth, maxHeight);
+                }
             }
-            onlyBoundsOptions.inJustDecodeBounds = true;
-            BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
-        } catch (IllegalArgumentException iae) {
-            onlyBoundsOptions.outWidth = -1;
-            onlyBoundsOptions.outHeight = -1;
-            Log.e(TAG, "error loading image", iae);
-        }
-        return onlyBoundsOptions;
+        });
     }
 
     private static int getPowerOfTwoForSampleRatio(double ratio) {
-        int k = Integer.highestOneBit((int) Math.floor(ratio));
+        final int k = Integer.highestOneBit((int) Math.floor(ratio));
         return Math.max(1, k);
     }
+
+    private static void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
+            ImageDecoder.Source source) {
+        final Size size = info.getSize();
+        final int originalSize = Math.max(size.getHeight(), size.getWidth());
+        final double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX)
+                ? originalSize * 1f / MAX_SAFE_ICON_SIZE_PX
+                : 1.0;
+        decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio));
+    }
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b562ef8..9712b4e 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -311,6 +311,15 @@
         return getDevicePolicyManager().getPasswordMinimumMetrics(userId);
     }
 
+    /**
+     * Returns the effective complexity for the user.
+     * @param userId  The user to return the complexity for.
+     * @return complexity level for the user.
+     */
+    public @DevicePolicyManager.PasswordComplexity int getRequestedPasswordComplexity(int userId) {
+        return getDevicePolicyManager().getAggregatedPasswordComplexityForUser(userId);
+    }
+
     public int getRequestedPasswordQuality(int userId) {
         return getDevicePolicyManager().getPasswordQuality(null, userId);
     }
diff --git a/core/jni/android_media_MicrophoneInfo.cpp b/core/jni/android_media_MicrophoneInfo.cpp
index 5bd808b..b70190f 100644
--- a/core/jni/android_media_MicrophoneInfo.cpp
+++ b/core/jni/android_media_MicrophoneInfo.cpp
@@ -56,8 +56,8 @@
     jobject jFrequencyResponses = NULL;
     jobject jChannelMappings = NULL;
 
-    jDeviceId = env->NewStringUTF(String8(microphoneInfo->getDeviceId()).string());
-    jAddress = env->NewStringUTF(String8(microphoneInfo->getAddress()).string());
+    jDeviceId = env->NewStringUTF(microphoneInfo->getDeviceId().c_str());
+    jAddress = env->NewStringUTF(microphoneInfo->getAddress().c_str());
     if (microphoneInfo->getGeometricLocation().size() != 3 ||
             microphoneInfo->getOrientation().size() != 3) {
         jStatus = nativeToJavaStatus(BAD_VALUE);
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index e7e9c31..6337680 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -41,14 +41,21 @@
     jmethodID dispatchVsync;
     jmethodID dispatchHotplug;
     jmethodID dispatchConfigChanged;
+    jmethodID dispatchFrameRateOverrides;
+
+    struct {
+        jclass clazz;
+        jmethodID init;
+    } frameRateOverrideClassInfo;
+
 } gDisplayEventReceiverClassInfo;
 
 
 class NativeDisplayEventReceiver : public DisplayEventDispatcher {
 public:
-    NativeDisplayEventReceiver(JNIEnv* env,
-            jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
-            jint configChanged);
+    NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
+                               const sp<MessageQueue>& messageQueue, jint vsyncSource,
+                               jint eventRegistration);
 
     void dispose();
 
@@ -64,16 +71,17 @@
     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
     void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
                                int32_t configId, nsecs_t vsyncPeriod) override;
+    void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
+                                    std::vector<FrameRateOverride> overrides) override;
     void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
 };
 
-
-NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
-        jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource,
-        jint configChanged) :
-        DisplayEventDispatcher(messageQueue->getLooper(),
-                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
-                static_cast<ISurfaceComposer::ConfigChanged>(configChanged)),
+NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
+                                                       const sp<MessageQueue>& messageQueue,
+                                                       jint vsyncSource, jint eventRegistration)
+      : DisplayEventDispatcher(messageQueue->getLooper(),
+                               static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
+                               static_cast<ISurfaceComposer::EventRegistration>(eventRegistration)),
         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
         mMessageQueue(messageQueue) {
     ALOGV("receiver %p ~ Initializing display event receiver.", this);
@@ -137,16 +145,48 @@
   mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
 }
 
-static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
-        jobject messageQueueObj, jint vsyncSource, jint configChanged) {
+void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
+        nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
+    if (receiverObj.get()) {
+        ALOGV("receiver %p ~ Invoking FrameRateOverride handler.", this);
+        const auto frameRateOverrideClass =
+                gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz;
+        const auto frameRateOverrideInit =
+                gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init;
+        auto frameRateOverrideInitObject =
+                env->NewObject(frameRateOverrideClass, frameRateOverrideInit, 0, 0);
+        auto frameRateOverrideArray = env->NewObjectArray(overrides.size(), frameRateOverrideClass,
+                                                          frameRateOverrideInitObject);
+        for (size_t i = 0; i < overrides.size(); i++) {
+            auto FrameRateOverrideObject =
+                    env->NewObject(frameRateOverrideClass, frameRateOverrideInit, overrides[i].uid,
+                                   overrides[i].frameRateHz);
+            env->SetObjectArrayElement(frameRateOverrideArray, i, FrameRateOverrideObject);
+        }
+
+        env->CallVoidMethod(receiverObj.get(),
+                            gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides, timestamp,
+                            displayId.value, frameRateOverrideArray);
+        ALOGV("receiver %p ~ Returned from FrameRateOverride handler.", this);
+    }
+
+    mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+}
+
+static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
+                        jint vsyncSource, jint eventRegistration) {
     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
     if (messageQueue == NULL) {
         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
         return 0;
     }
 
-    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
-            receiverWeak, messageQueue, vsyncSource, configChanged);
+    sp<NativeDisplayEventReceiver> receiver =
+            new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
+                                           eventRegistration);
     status_t status = receiver->initialize();
     if (status) {
         String8 message;
@@ -205,6 +245,18 @@
             gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
     gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env,
            gDisplayEventReceiverClassInfo.clazz, "dispatchConfigChanged", "(JJI)V");
+    gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
+            GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
+                             "dispatchFrameRateOverrides",
+                             "(JJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V");
+
+    jclass frameRateOverrideClazz =
+            FindClassOrDie(env, "android/view/DisplayEventReceiver$FrameRateOverride");
+    gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz =
+            MakeGlobalRefOrDie(env, frameRateOverrideClazz);
+    gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init =
+            GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
+                             "<init>", "(IF)V");
 
     return res;
 }
diff --git a/core/proto/Android.bp b/core/proto/Android.bp
deleted file mode 100644
index 3b891d6..0000000
--- a/core/proto/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// C++ library for Bluetooth platform wide protobuf definitions
-cc_library_static {
-    name: "libbt-platform-protos-lite",
-    host_supported: true,
-    proto: {
-        export_proto_headers: true,
-        type: "lite",
-    },
-    srcs: [
-        "android/bluetooth/a2dp/enums.proto",
-        "android/bluetooth/enums.proto",
-        "android/bluetooth/hci/enums.proto",
-        "android/bluetooth/hfp/enums.proto",
-        "android/bluetooth/smp/enums.proto",
-    ],
-}
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 542d26f..748b4b4 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -25,3 +25,8 @@
 
 # Graphics stats
 jreck@google.com
+
+# Accessibility
+pweaver@google.com
+hongmingjin@google.com
+cbrower@google.com
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
deleted file mode 100644
index 722194b..0000000
--- a/core/proto/android/app/enums.proto
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.app;
-
-option java_outer_classname = "AppProtoEnums";
-option java_multiple_files = true;
-
-// ActivityManagerInternal.java's APP_TRANSITION reasons.
-enum AppTransitionReasonEnum {
-    APP_TRANSITION_REASON_UNKNOWN = 0;
-    // The transition was started because we drew the splash screen.
-    APP_TRANSITION_SPLASH_SCREEN = 1;
-    // The transition was started because we all app windows were drawn.
-    APP_TRANSITION_WINDOWS_DRAWN = 2;
-    // The transition was started because of a timeout.
-    APP_TRANSITION_TIMEOUT = 3;
-    // The transition was started because of a we drew a task snapshot.
-    APP_TRANSITION_SNAPSHOT = 4;
-    // The transition was started because it was a recents animation and we only needed to wait on
-    // the wallpaper.
-    APP_TRANSITION_RECENTS_ANIM = 5;
-}
-
-// ActivityManager.java PROCESS_STATEs
-// Next tag: 1021
-enum ProcessStateEnum {
-    // Unlike the ActivityManager PROCESS_STATE values, the ordering and numerical values
-    // here are completely fixed and arbitrary. Order is irrelevant.
-    // No attempt need be made to keep them in sync.
-    // The values here must not be modified. Any new process states can be appended to the end.
-
-    // Process state that is unknown to this proto file (i.e. is not mapped
-    // by ActivityManager.processStateAmToProto()). Can only happen if there's a bug in the mapping.
-    PROCESS_STATE_UNKNOWN_TO_PROTO = 998;
-    // Not a real process state.
-    PROCESS_STATE_UNKNOWN = 999;
-    // Process is a persistent system process.
-    PROCESS_STATE_PERSISTENT = 1000;
-    // Process is a persistent system process and is doing UI.
-    PROCESS_STATE_PERSISTENT_UI = 1001;
-    // Process is hosting the current top activities. Note that this covers
-    // all activities that are visible to the user.
-    PROCESS_STATE_TOP = 1002;
-    // Process is bound to a TOP app.
-    PROCESS_STATE_BOUND_TOP = 1020;
-    // Process is hosting a foreground service.
-    PROCESS_STATE_FOREGROUND_SERVICE = 1003;
-    // Process is hosting a service bound by the system or another foreground app.
-    PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 1004;
-    // Process is important to the user, and something they are aware of.
-    PROCESS_STATE_IMPORTANT_FOREGROUND = 1005;
-    // Process is important to the user, but not something they are aware of.
-    PROCESS_STATE_IMPORTANT_BACKGROUND = 1006;
-    // Process is in the background transient so we will try to keep running.
-    PROCESS_STATE_TRANSIENT_BACKGROUND = 1007;
-    // Process is in the background running a backup/restore operation.
-    PROCESS_STATE_BACKUP = 1008;
-    // Process is in the background running a service. Unlike oom_adj, this
-    // level is used for both the normal running in background state and the
-    // executing operations state.
-    PROCESS_STATE_SERVICE = 1009;
-    // Process is in the background running a receiver. Note that from the
-    // perspective of oom_adj, receivers run at a higher foreground level, but
-    // for our prioritization here that is not necessary and putting them
-    // below services means many fewer changes in some process states as they
-    // receive broadcasts.
-    PROCESS_STATE_RECEIVER = 1010;
-    // Same as PROCESS_STATE_TOP but while device is sleeping.
-    PROCESS_STATE_TOP_SLEEPING = 1011;
-    // Process is in the background, but it can't restore its state so we want
-    // to try to avoid killing it.
-    PROCESS_STATE_HEAVY_WEIGHT = 1012;
-    // Process is in the background but hosts the home activity.
-    PROCESS_STATE_HOME = 1013;
-    // Process is in the background but hosts the last shown activity.
-    PROCESS_STATE_LAST_ACTIVITY = 1014;
-    // Process is being cached for later use and contains activities.
-    PROCESS_STATE_CACHED_ACTIVITY = 1015;
-    // Process is being cached for later use and is a client of another cached
-    // process that contains activities.
-    PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1016;
-    // Process is being cached for later use and has an activity that corresponds
-    // to an existing recent task.
-    PROCESS_STATE_CACHED_RECENT = 1017;
-    // Process is being cached for later use and is empty.
-    PROCESS_STATE_CACHED_EMPTY = 1018;
-    // Process does not exist.
-    PROCESS_STATE_NONEXISTENT = 1019;
-}
-
-// AppOpsManager.java - operation ids for logging
-enum AppOpEnum {
-    APP_OP_NONE = -1;
-    APP_OP_COARSE_LOCATION = 0;
-    APP_OP_FINE_LOCATION = 1;
-    APP_OP_GPS = 2;
-    APP_OP_VIBRATE = 3;
-    APP_OP_READ_CONTACTS = 4;
-    APP_OP_WRITE_CONTACTS = 5;
-    APP_OP_READ_CALL_LOG = 6;
-    APP_OP_WRITE_CALL_LOG = 7;
-    APP_OP_READ_CALENDAR = 8;
-    APP_OP_WRITE_CALENDAR = 9;
-    APP_OP_WIFI_SCAN = 10;
-    APP_OP_POST_NOTIFICATION = 11;
-    APP_OP_NEIGHBORING_CELLS = 12;
-    APP_OP_CALL_PHONE = 13;
-    APP_OP_READ_SMS = 14;
-    APP_OP_WRITE_SMS = 15;
-    APP_OP_RECEIVE_SMS = 16;
-    APP_OP_RECEIVE_EMERGENCY_SMS = 17;
-    APP_OP_RECEIVE_MMS = 18;
-    APP_OP_RECEIVE_WAP_PUSH = 19;
-    APP_OP_SEND_SMS = 20;
-    APP_OP_READ_ICC_SMS = 21;
-    APP_OP_WRITE_ICC_SMS = 22;
-    APP_OP_WRITE_SETTINGS = 23;
-    APP_OP_SYSTEM_ALERT_WINDOW = 24;
-    APP_OP_ACCESS_NOTIFICATIONS = 25;
-    APP_OP_CAMERA = 26;
-    APP_OP_RECORD_AUDIO = 27;
-    APP_OP_PLAY_AUDIO = 28;
-    APP_OP_READ_CLIPBOARD = 29;
-    APP_OP_WRITE_CLIPBOARD = 30;
-    APP_OP_TAKE_MEDIA_BUTTONS = 31;
-    APP_OP_TAKE_AUDIO_FOCUS = 32;
-    APP_OP_AUDIO_MASTER_VOLUME = 33;
-    APP_OP_AUDIO_VOICE_VOLUME = 34;
-    APP_OP_AUDIO_RING_VOLUME = 35;
-    APP_OP_AUDIO_MEDIA_VOLUME = 36;
-    APP_OP_AUDIO_ALARM_VOLUME = 37;
-    APP_OP_AUDIO_NOTIFICATION_VOLUME = 38;
-    APP_OP_AUDIO_BLUETOOTH_VOLUME = 39;
-    APP_OP_WAKE_LOCK = 40;
-    APP_OP_MONITOR_LOCATION = 41;
-    APP_OP_MONITOR_HIGH_POWER_LOCATION = 42;
-    APP_OP_GET_USAGE_STATS = 43;
-    APP_OP_MUTE_MICROPHONE = 44;
-    APP_OP_TOAST_WINDOW = 45;
-    APP_OP_PROJECT_MEDIA = 46;
-    APP_OP_ACTIVATE_VPN = 47;
-    APP_OP_WRITE_WALLPAPER = 48;
-    APP_OP_ASSIST_STRUCTURE = 49;
-    APP_OP_ASSIST_SCREENSHOT = 50;
-    APP_OP_READ_PHONE_STATE = 51;
-    APP_OP_ADD_VOICEMAIL = 52;
-    APP_OP_USE_SIP = 53;
-    APP_OP_PROCESS_OUTGOING_CALLS = 54;
-    APP_OP_USE_FINGERPRINT = 55;
-    APP_OP_BODY_SENSORS = 56;
-    APP_OP_READ_CELL_BROADCASTS = 57;
-    APP_OP_MOCK_LOCATION = 58;
-    APP_OP_READ_EXTERNAL_STORAGE = 59;
-    APP_OP_WRITE_EXTERNAL_STORAGE = 60;
-    APP_OP_TURN_SCREEN_ON = 61;
-    APP_OP_GET_ACCOUNTS = 62;
-    APP_OP_RUN_IN_BACKGROUND = 63;
-    APP_OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
-    APP_OP_READ_PHONE_NUMBERS = 65;
-    APP_OP_REQUEST_INSTALL_PACKAGES = 66;
-    APP_OP_PICTURE_IN_PICTURE = 67;
-    APP_OP_INSTANT_APP_START_FOREGROUND = 68;
-    APP_OP_ANSWER_PHONE_CALLS = 69;
-    APP_OP_RUN_ANY_IN_BACKGROUND = 70;
-    APP_OP_CHANGE_WIFI_STATE = 71;
-    APP_OP_REQUEST_DELETE_PACKAGES = 72;
-    APP_OP_BIND_ACCESSIBILITY_SERVICE = 73;
-    APP_OP_ACCEPT_HANDOVER = 74;
-    APP_OP_MANAGE_IPSEC_TUNNELS = 75;
-    APP_OP_START_FOREGROUND = 76;
-    APP_OP_BLUETOOTH_SCAN = 77;
-    APP_OP_USE_BIOMETRIC = 78;
-    APP_OP_ACTIVITY_RECOGNITION = 79;
-    APP_OP_SMS_FINANCIAL_TRANSACTIONS = 80;
-    APP_OP_READ_MEDIA_AUDIO = 81;
-    APP_OP_WRITE_MEDIA_AUDIO = 82;
-    APP_OP_READ_MEDIA_VIDEO = 83;
-    APP_OP_WRITE_MEDIA_VIDEO = 84;
-    APP_OP_READ_MEDIA_IMAGES = 85;
-    APP_OP_WRITE_MEDIA_IMAGES = 86;
-    APP_OP_LEGACY_STORAGE = 87;
-    APP_OP_ACCESS_ACCESSIBILITY = 88;
-    APP_OP_READ_DEVICE_IDENTIFIERS = 89;
-    APP_OP_ACCESS_MEDIA_LOCATION = 90;
-    APP_OP_QUERY_ALL_PACKAGES = 91;
-    APP_OP_MANAGE_EXTERNAL_STORAGE = 92;
-    APP_OP_INTERACT_ACROSS_PROFILES = 93;
-    APP_OP_ACTIVATE_PLATFORM_VPN = 94;
-    APP_OP_LOADER_USAGE_STATS = 95;
-    APP_OP_DEPRECATED_1 = 96 [deprecated = true];
-    APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
-    APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98;
-    APP_OP_NO_ISOLATED_STORAGE = 99;
-    APP_OP_PHONE_CALL_MICROPHONE = 100;
-    APP_OP_PHONE_CALL_CAMERA = 101;
-    APP_OP_RECORD_AUDIO_HOTWORD = 102;
-    APP_OP_MANAGE_ONGOING_CALLS = 103;
-    APP_OP_MANAGE_CREDENTIALS = 104;
-}
diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto
deleted file mode 100644
index 41863bb..0000000
--- a/core/proto/android/app/job/enums.proto
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.app.job;
-
-// This file is for JobScheduler enums inside the app directory. If you're
-// adding enums for system-server-side code, use the file in
-// frameworks/base/core/proto/android/server/job.
-option java_outer_classname = "JobProtoEnums";
-option java_multiple_files = true;
-
-// Reasons a job is stopped.
-// Primarily used in android.app.job.JobParameters.java.
-enum StopReasonEnum {
-    STOP_REASON_UNKNOWN = -1;
-    STOP_REASON_CANCELLED = 0;
-    STOP_REASON_CONSTRAINTS_NOT_SATISFIED = 1;
-    STOP_REASON_PREEMPT = 2;
-    STOP_REASON_TIMEOUT = 3;
-    STOP_REASON_DEVICE_IDLE = 4;
-    STOP_REASON_DEVICE_THERMAL = 5;
-    STOP_REASON_RESTRICTED_BUCKET = 6;
-}
diff --git a/core/proto/android/app/media_output_enum.proto b/core/proto/android/app/media_output_enum.proto
deleted file mode 100644
index 0d42fb7..0000000
--- a/core/proto/android/app/media_output_enum.proto
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.app.settings.mediaoutput;
-option java_multiple_files = true;
-
-/**
- * The medium type specified in an output switching operation.
- */
-enum MediumType {
-    UNKNOWN_TYPE = 0;
-    BUILTIN_SPEAKER = 1;
-    WIRED_3POINT5_MM_AUDIO = 100;
-    WIRED_3POINT5_MM_HEADSET = 101;
-    WIRED_3POINT5_MM_HEADPHONES = 102;
-    USB_C_AUDIO = 200;
-    USB_C_DEVICE = 201;
-    USB_C_HEADSET = 202;
-    USB_C_ACCESSORY = 203;
-    USB_C_DOCK = 204;
-    USB_C_HDMI = 205;
-    BLUETOOTH = 300;
-    BLUETOOTH_HEARING_AID = 301;
-    BLUETOOTH_A2DP = 302;
-    REMOTE_SINGLE = 400;
-    REMOTE_TV = 401;
-    REMOTE_SPEAKER = 402;
-    REMOTE_GROUP = 500;
-    REMOTE_DYNAMIC_GROUP = 501;
-};
-
-/**
- * The result of an output switching operation.
- */
-enum SwitchResult {
-    ERROR = 0;
-    OK = 1;
-};
-
-/**
- * The sub result of an output switching operation.
- */
-enum SubResult {
-    UNKNOWN_ERROR = 0;
-    NO_ERROR = 1;
-    REJECTED = 2;
-    NETWORK_ERROR = 3;
-    ROUTE_NOT_AVAILABLE = 4;
-    INVALID_COMMAND = 5;
-}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
deleted file mode 100644
index a2a7649..0000000
--- a/core/proto/android/app/settings_enums.proto
+++ /dev/null
@@ -1,2794 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.app.settings;
-option java_multiple_files = true;
-
-/**
- * The action performed in this event
- */
-enum Action {
-    ACTION_UNKNOWN = 0;
-    PAGE_VISIBLE = 1;
-    PAGE_HIDE = 2;
-
-    // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
-    //   SUBTYPE: true if connecting to a saved network, false if not
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_WIFI_CONNECT = 135;
-
-    // ACTION: Settings > Wi-Fi > [Long press network] > Forget network
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_WIFI_FORGET = 137;
-
-    // ACTION: Settings > Wi-Fi > Toggle off
-    //   SUBTYPE: true if connected to network before toggle, false if not
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_WIFI_OFF = 138;
-
-    // ACTION: Settings > Wi-Fi > Toggle on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_WIFI_ON = 139;
-
-    // ACTION: Settings > Bluetooth > Overflow > Rename this device
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_BLUETOOTH_RENAME = 161;
-
-    // ACTION: Settings > Bluetooth > Overflow > Show received files
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_BLUETOOTH_FILES = 162;
-
-    // ACTION: DND Settings > Priority only allows > Reminder toggle
-    //   SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ZEN_ALLOW_REMINDERS = 167;
-
-    // ACTION: DND Settings > Priority only allows > Event toggle
-    //   SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ZEN_ALLOW_EVENTS = 168;
-
-    // ACTION: DND Settings > Priority only allows > Messages
-    //   SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ZEN_ALLOW_MESSAGES = 169;
-
-    // ACTION: DND Settings > Priority only allows > Calls
-    //   SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ZEN_ALLOW_CALLS = 170;
-
-    // ACTION: DND Settings > Priority only allows > Repeat callers toggle
-    //   SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
-
-    // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ZEN_DELETE_RULE_OK = 175;
-
-    // ACTION: Settings > More > Airplane mode toggle
-    //   SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_AIRPLANE_TOGGLE = 177;
-
-    // ACTION: Settings > Data usage > Cellular data toggle
-    //   SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_CELL_DATA_TOGGLE = 178;
-
-    // ACTION: Settings > Display > When device is rotated
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ROTATION_LOCK = 203;
-
-    // OPEN: Settings > Search > Perform search
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_SEARCH_RESULTS = 226;
-
-    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_FINGERPRINT_DELETE = 253;
-
-    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_FINGERPRINT_RENAME = 254;
-
-    // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report
-    // CATEGORY: SETTINGS
-    // OS: N
-    // Interactive bug report initiated from Settings.
-    ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
-
-    // ACTION: Settings -> Developer Options -> Take bug report -> Full report
-    // CATEGORY: SETTINGS
-    // OS: N
-    // Interactive bug report initiated from Settings.
-    ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
-
-    // click on collapsed conditional or clicks expand button
-    ACTION_SETTINGS_CONDITION_EXPAND = 373;
-
-    // click main area of expanded conditional
-    ACTION_SETTINGS_CONDITION_CLICK = 375;
-
-    // click a direct button on expanded conditional
-    ACTION_SETTINGS_CONDITION_BUTTON = 376;
-
-    // Action: user enable / disabled data saver using Settings
-    // OPEN: Settings -> Data Usage -> Data saver -> On/off toggle
-    // VALUE: 1 for enabled, 0 for disabled
-    // CATEGORY: SETTINGS
-    // OS: N
-    ACTION_DATA_SAVER_MODE = 394;
-
-    // User whitelisted an app for Data Saver mode; action pass package name of app
-    // Action: user enable / disabled data saver using Settings
-    // OPEN: Settings -> Data Usage -> Data saver -> Unrestricted data access > APP toggle turned on
-    //       or
-    //       Settings -> Apps -> APP -> Data usage -> Unrestricted data usage toggle turned on
-    // VALUE: package name of APP
-    // CATEGORY: SETTINGS
-    // OS: N
-    ACTION_DATA_SAVER_WHITELIST = 395;
-
-    // User blacklisted an app for Data Saver mode; action pass package name of app
-    // OPEN: Settings -> Apps -> APP -> Data usage -> Background data toggle turned off
-    // VALUE: package name of APP
-    // CATEGORY: SETTINGS
-    // OS: N
-    ACTION_DATA_SAVER_BLACKLIST = 396;
-
-    // ACTION: Settings -> Storage -> Manage storage -> Click Storage Manager
-    //   SUBTYPE: false is off, true is on
-    ACTION_TOGGLE_STORAGE_MANAGER = 489;
-
-    // OPEN: Settings > Display -> Ambient Display
-    // CATEGORY: SETTINGS
-    ACTION_AMBIENT_DISPLAY = 495;
-
-    // ACTION: Allow Battery optimization for an app
-    APP_SPECIAL_PERMISSION_BATTERY_ALLOW = 764;
-
-    // ACTION: Deny Battery optimization for an app
-    APP_SPECIAL_PERMISSION_BATTERY_DENY = 765;
-
-    // ACTION: Enable Device Admin app
-    APP_SPECIAL_PERMISSION_ADMIN_ALLOW = 766;
-
-    // ACTION: Disable Device Admin app
-    APP_SPECIAL_PERMISSION_ADMIN_DENY = 767;
-
-    // ACTION: Allow "Do Not Disturb access" for an app
-    APP_SPECIAL_PERMISSION_DND_ALLOW = 768;
-
-    // ACTION: Deny "Do Not Disturb access" for an app
-    APP_SPECIAL_PERMISSION_DND_DENY = 769;
-
-    // ACTION: Allow "Draw over other apps" for an app
-    APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770;
-
-    // ACTION: Deny "Display over other apps" for an app
-    APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771;
-
-    // ACTION: Allow "VR helper services" for an app
-    APP_SPECIAL_PERMISSION_VRHELPER_ALLOW = 772;
-
-    // ACTION: Deny "VR helper services" for an app
-    APP_SPECIAL_PERMISSION_VRHELPER_DENY = 773;
-
-    // ACTION: Allow "Modify system settings" for an app
-    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW = 774;
-
-    // ACTION: Deny "Modify system settings" for an app
-    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY = 775;
-
-    // ACTION: Allow "Notification access" for an app
-    APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW = 776;
-
-    // ACTION: Deny "Notification access" for an app
-    APP_SPECIAL_PERMISSION_NOTIVIEW_DENY = 777;
-
-    // ACTION: "Premium SMS access" for an app - "ask user" option
-    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK = 778;
-
-    // ACTION: "Premium SMS access" for an app - "never allow" option
-    APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY = 779;
-
-    // ACTION: "Premium SMS access" for an app - "always allow" option
-    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW = 780;
-
-    // ACTION: Allow "Unrestricted data access" for an app
-    APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW = 781;
-
-    // ACTION: Deny "Unrestricted data access" for an app
-    APP_SPECIAL_PERMISSION_UNL_DATA_DENY = 782;
-
-    // ACTION: Allow "Usage access" for an app
-    APP_SPECIAL_PERMISSION_USAGE_VIEW_ALLOW = 783;
-
-    // ACTION: Deny "Usage access" for an app
-    APP_SPECIAL_PERMISSION_USAGE_VIEW_DENY = 784;
-
-    // ACTION: "Force stop" action on an app
-    ACTION_APP_FORCE_STOP = 807;
-
-    // ACTION: Allow "Enable picture-in-picture" for an app
-    APP_PICTURE_IN_PICTURE_ALLOW = 813;
-
-    // ACTION: Create a Settings shortcut item.
-    ACTION_SETTINGS_CREATE_SHORTCUT = 829;
-
-    // ACTION: A tile in Settings information architecture is clicked
-    ACTION_SETTINGS_TILE_CLICK = 830;
-
-    // ACTION: Settings advanced button is expanded
-    ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND = 834;
-
-    // ACTION: Deny "Enable picture-in-picture" for an app
-    APP_PICTURE_IN_PICTURE_DENY = 814;
-
-    // ACTION: Settings -> Display -> Theme
-    ACTION_THEME = 816;
-
-    // ACTION: Settings > About device > Build number
-    ACTION_SETTINGS_BUILD_NUMBER_PREF = 847;
-
-    // ACTION: Settings > Battery > Menu > Optimization
-    ACTION_SETTINGS_MENU_BATTERY_OPTIMIZATION = 851;
-
-    // ACTION: Settings > Battery > Menu > Apps Toggle
-    ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE = 852;
-
-    // ACTION: Settings > Any preference is changed
-    ACTION_SETTINGS_PREFERENCE_CHANGE = 853;
-
-    // ACTION: Settings > Connected devices > Bluetooth -> Available devices
-    ACTION_SETTINGS_BLUETOOTH_PAIR = 866;
-
-    // ACTION: Settings > Connected devices > Bluetooth -> Paired devices
-    ACTION_SETTINGS_BLUETOOTH_CONNECT = 867;
-
-    // ACTION: Settings > Connected devices > Bluetooth -> Connected device
-    ACTION_SETTINGS_BLUETOOTH_DISCONNECT = 868;
-
-    // ACTION: Settings > Connected devices > Bluetooth -> Error dialog
-    ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR = 869;
-
-    // ACTION: Settings > Connected devices > Bluetooth master switch Toggle
-    ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE = 870;
-
-    // ACTION: Settings > App detail > Uninstall
-    ACTION_SETTINGS_UNINSTALL_APP = 872;
-
-    // ACTION: Settings > App detail > Uninstall Device admin app
-    ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN = 873;
-
-    // ACTION: Settings > App detail > Disable app
-    ACTION_SETTINGS_DISABLE_APP = 874;
-
-    // ACTION: Settings > App detail > Enable app
-    ACTION_SETTINGS_ENABLE_APP = 875;
-
-    // ACTION: Settings > App detail > Clear data
-    ACTION_SETTINGS_CLEAR_APP_DATA = 876;
-
-    // ACTION: Settings > App detail > Clear cache
-    ACTION_SETTINGS_CLEAR_APP_CACHE = 877;
-
-    // ACTION: Logs pressing the "Clear app" button in the app info settings page for an instant
-    // app.
-    // VALUE: The package name of the app
-    ACTION_SETTINGS_CLEAR_INSTANT_APP = 923;
-
-    // OPEN: Assist Gesture training intro in Settings
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    SETTINGS_ASSIST_GESTURE_TRAINING_INTRO = 991;
-
-    // OPEN: Assist Gesture training enrolling in Settings
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    SETTINGS_ASSIST_GESTURE_TRAINING_ENROLLING = 992;
-
-    // OPEN: Assist Gesture training finished in Settings
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    SETTINGS_ASSIST_GESTURE_TRAINING_FINISHED = 993;
-
-    // ACTION: Update default app from Settings
-    ACTION_SETTINGS_UPDATE_DEFAULT_APP = 1000;
-
-    // ACTION: Settings > Wi-Fi > [Long press network] > Sign in to network
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    ACTION_WIFI_SIGNIN = 1008;
-
-    // ACTION: Settings > Notification Settings > Open application notification
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    ACTION_OPEN_APP_NOTIFICATION_SETTING = 1016;
-
-    // ACTION: Settings > App Info > Open app settings
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    ACTION_OPEN_APP_SETTING = 1017;
-
-    // ACTION: Collect PSD Signals
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    ACTION_PSD_LOADER = 1019;
-
-    // OPEN: Settings > Trampoline Intent > Settings page
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    TRAMPOLINE_SETTINGS_EVENT = 1033;
-
-    // ACTION: Logged when user tries to pair a Bluetooth device without name from Settings app
-    // CATEGORY: SETTINGS
-    // OS: O MR
-    ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES = 1096;
-
-    // ACTION: Settings > Network & Internet > Mobile network > Network
-    // CATEGORY: SETTINGS
-    ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK = 1210;
-
-    // ACTION: DND Settings > Priority only allows > Alarms toggle
-    // SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_ALLOW_ALARMS = 1226;
-
-    // ACTION: DND Settings > Priority only allows > Media toggle
-    // SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_ALLOW_MEDIA = 1227;
-
-    // ACTION: A private dns mode been selected by user
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_PRIVATE_DNS_MODE = 1249;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name > OK
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK = 1267;
-
-    // OPEN: Settings > Sound > Do Not Disturb > TURN ON NOW/TURN OFF NOW
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_TOGGLE_DND_BUTTON = 1268;
-
-    // ACTION: DND Settings > What to block > full screen intents
-    //   SUBTYPE: false is allowed, true is blocked
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACTION_ZEN_BLOCK_FULL_SCREEN_INTENTS = 1332;
-
-    // ACTION: DND Settings > What to block
-    //   SUBTYPE: false is allowed, true is blocked
-    // OS: P
-    ACTION_ZEN_BLOCK_LIGHT = 1333;
-
-    // ACTION: DND Settings > What to block
-    //   SUBTYPE: false is allowed, true is blocked
-    // OS: P
-    ACTION_ZEN_BLOCK_PEEK = 1334;
-
-    // ACTION: DND Settings > What to block
-    //   SUBTYPE: false is allowed, true is blocked
-    // OS: P
-    ACTION_ZEN_BLOCK_STATUS = 1335;
-
-    // ACTION: DND Settings > What to block
-    //   SUBTYPE: false is allowed, true is blocked
-    // OS: P
-    ACTION_ZEN_BLOCK_BADGE = 1336;
-
-    // ACTION: DND Settings > What to block
-    //   SUBTYPE: false is allowed, true is blocked
-    // OS: P
-    ACTION_ZEN_BLOCK_AMBIENT = 1337;
-
-    // ACTION: DND Settings > What to block
-    //   SUBTYPE: false is allowed, true is blocked
-    // OS: P
-    ACTION_ZEN_BLOCK_NOTIFICATION_LIST = 1338;
-
-    // ACTION: DND Settings > Priority only allows > System toggle
-    // SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_ALLOW_SYSTEM = 1340;
-
-    // ACTION: Settings > Battery settings > Battery tip > App restriction tip
-    // OS: P
-    ACTION_APP_RESTRICTION_TIP = 1347;
-
-    // ACTION: Settings > Battery settings > Battery tip > High usage tip
-    // OS: P
-    ACTION_HIGH_USAGE_TIP = 1348;
-
-    // ACTION: Settings > Battery settings > Battery tip > Summary tip
-    // OS: P
-    ACTION_SUMMARY_TIP = 1349;
-
-    // ACTION: Settings > Battery settings > Battery tip > Smart battery tip
-    // OS: P
-    ACTION_SMART_BATTERY_TIP = 1350;
-
-    // ACTION: Settings > Battery settings > Battery tip > Early warning tip
-    // OS: P
-    ACTION_EARLY_WARNING_TIP = 1351;
-
-    // ACTION: Settings > Battery settings > Battery tip > Low battery tip
-    // OS: P
-    ACTION_LOW_BATTERY_TIP = 1352;
-
-    // ACTION: Settings > Battery settings > Battery tip > App restriction list shown
-    // OS: P
-    ACTION_APP_RESTRICTION_TIP_LIST = 1353;
-
-    // ACTION: Settings > Battery settings > Battery tip > High usage list shown
-    // OS: P
-    ACTION_HIGH_USAGE_TIP_LIST = 1354;
-
-    // ACTION: Settings > Battery settings > Battery tip > Open app restriction page
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_TIP_OPEN_APP_RESTRICTION_PAGE = 1361;
-
-    // ACTION: Settings > Battery settings > Battery tip > Restrict app
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_TIP_RESTRICT_APP = 1362;
-
-    // ACTION: Settings > Battery settings > Battery tip > Unrestrict app
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_TIP_UNRESTRICT_APP = 1363;
-
-    // ACTION: Settings > Battery settings > Battery tip > Open smart battery page
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_TIP_OPEN_SMART_BATTERY = 1364;
-
-    // ACTION: Settings > Battery settings > Battery tip > Turn on battery saver
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_TIP_TURN_ON_BATTERY_SAVER = 1365;
-
-    // ACTION: Settings > Anomaly receiver > Anomaly received
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ANOMALY_TRIGGERED = 1367;
-
-    // ACTION: A Settings Slice is requested
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_SETTINGS_SLICE_REQUESTED = 1371;
-
-    // ACTION: A Settings Slice is updated with new value
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_SETTINGS_SLICE_CHANGED = 1372;
-
-    // OPEN: DND onboarding activity > Ok button
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_ONBOARDING_OK = 1378;
-
-    // OPEN: DND onboarding activity > Settings link
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_ONBOARDING_SETTINGS = 1379;
-
-    // ACTION: Settings > Anomaly receiver > Anomaly ignored, don't show up in battery settings
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ANOMALY_IGNORED = 1387;
-
-    // ACTION: Settings > Battery settings > Battery tip > Open battery saver page
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_TIP_OPEN_BATTERY_SAVER_PAGE = 1388;
-
-    // ACTION: DND Settings > What to block
-    // OS: P
-    ACTION_ZEN_SOUND_ONLY = 1396;
-
-    // ACTION: DND Settings > Notifications
-    // OS: P
-    ACTION_ZEN_SOUND_AND_VIS_EFFECTS = 1397;
-
-    // ACTION: DND Settings > Notifications
-    // OS: P
-    ACTION_ZEN_SHOW_CUSTOM = 1398;
-
-    // ACTION: DND Settings > Notifications
-    // OS: P
-    ACTION_ZEN_CUSTOM = 1399;
-
-    // OPEN: DND onboarding activity > don't update button
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS = 1406;
-
-    // ACTION: Storage initialization wizard initialization choice of external/portable
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_STORAGE_INIT_EXTERNAL = 1407;
-
-    // ACTION: Storage initialization wizard initialization choice of internal/adoptable
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_STORAGE_INIT_INTERNAL = 1408;
-
-    // ACTION: Storage initialization wizard benchmark fast choice of continue
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_STORAGE_BENCHMARK_FAST_CONTINUE = 1409;
-
-    // ACTION: Storage initialization wizard benchmark slow choice of continue
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_STORAGE_BENCHMARK_SLOW_CONTINUE = 1410;
-
-    // ACTION: Storage initialization wizard benchmark slow choice of abort
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_STORAGE_BENCHMARK_SLOW_ABORT = 1411;
-
-    // ACTION: Storage initialization wizard migration choice of now
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_STORAGE_MIGRATE_NOW = 1412;
-
-    // ACTION: Storage initialization wizard migration choice of later
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACTION_STORAGE_MIGRATE_LATER = 1413;
-
-    // OPEN: Settings > Sound > Switch a2dp devices dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_SWITCH_A2DP_DEVICES = 1415;
-
-
-    // OPEN: Settings > Sound > Switch hfp devices dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_SWITCH_HFP_DEVICES = 1416;
-
-    // OPEN: QS Sensor Privacy Mode tile shown
-    // ACTION: QS Sensor Privacy Mode tile tapped
-    // SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: QUICK_SETTINGS
-    // OS: Q
-    QS_SENSOR_PRIVACY = 1598;
-
-    // ACTION: Tap & Pay -> Default Application Setting -> Use Forground
-    ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
-
-    // ACTION: Tap & Pay -> Default Application Setting -> Use Default
-    ACTION_NFC_PAYMENT_ALWAYS_SETTING = 1623;
-
-    // ACTION: Settings > Search Bar > Avatar
-    // CATEGORY: SETTINGS
-    // OS: Q
-    CLICK_ACCOUNT_AVATAR = 1643;
-
-    // ACTION: Set new password (action intent android.app.action.SET_NEW_PASSWORD)
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ACTION_SET_NEW_PASSWORD = 1645;
-
-    // ACTION: Set new password (action intent android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD)
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = 1646;
-
-    // ACTION: An interaction with a Slice or other component in the Panel.
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ACTION_PANEL_INTERACTION = 1658;
-
-    // ACTION: Show Contextual homepage. Log total loading latency.
-    ACTION_CONTEXTUAL_HOME_SHOW = 1662;
-
-    // ACTION: Contextual card displays
-    ACTION_CONTEXTUAL_CARD_SHOW = 1663;
-
-    // ACTION: Contextual cards are eligible to be shown, but don't rank high
-    ACTION_CONTEXTUAL_CARD_NOT_SHOW = 1664;
-
-    // ACTION: Settings > long press a card, and click dismiss
-    // Contextual card is dismissed
-    ACTION_CONTEXTUAL_CARD_DISMISS = 1665;
-
-    // ACTION: Settings > click a card
-    // Contextual card is clicked
-    ACTION_CONTEXTUAL_CARD_CLICK = 1666;
-
-    // Mapping: go/at-mapping
-    ACTION_ATSG = 1674;
-
-    ACTION_ATPG = 1675;
-
-    ACTION_ATCLPB = 1676;
-
-    ACTION_ATCGIB = 1677;
-
-    ACTION_ATCPAB = 1678;
-
-    ACTION_ATCSAUC = 1679;
-
-    ACTION_ATCSCUC = 1680;
-
-    ACTION_ATCHNUC = 1681;
-
-    // ACTION: Individual contextual card loading time
-    ACTION_CONTEXTUAL_CARD_LOAD = 1684;
-
-    //ACTION: Contextual card loading timeout
-    ACTION_CONTEXTUAL_CARD_LOAD_TIMEOUT = 1685;
-
-    //ACTION: Log result for each card's eligibility check
-    ACTION_CONTEXTUAL_CARD_ELIGIBILITY = 1686;
-
-    // ACTION: Display white balance setting enabled or disabled.
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ACTION_DISPLAY_WHITE_BALANCE_SETTING_CHANGED = 1703;
-
-    // ACTION: Share a Wi-Fi network by generating a QR code
-    ACTION_SETTINGS_SHARE_WIFI_QR_CODE = 1710;
-
-    // ACTION: Connect to a Wi-Fi network by scanning a QR code
-    ACTION_SETTINGS_ENROLL_WIFI_QR_CODE = 1711;
-
-    // ACTION: Share Wi-Fi hotspot by generating a QR code
-    ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE = 1712;
-
-    // ACTION: Settings > Initialize Search bar > Verify Slice > Invalid data
-    ACTION_VERIFY_SLICE_ERROR_INVALID_DATA = 1725;
-
-    // ACTION: Settings > Initialize Search bar > Verify Slice > Parsing error
-    ACTION_VERIFY_SLICE_PARSING_ERROR = 1726;
-
-    // ACTION: Settings > Initialize Search bar > Verify Slice > Other exception
-    ACTION_VERIFY_SLICE_OTHER_EXCEPTION = 1727;
-
-    // Custom tag to evaluate the consuming time of the Controller.updateState.
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_CONTROLLER_UPDATE_STATE = 1728;
-
-    // Custom tag to evaluate the consuming time from onAttach to
-    // DashboardFragment.updatePreferenceStates.
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_DASHBOARD_VISIBLE_TIME = 1729;
-
-    // ACTION: Allow "Access all files" for an app
-    APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_ALLOW = 1730;
-
-    // ACTION: Deny "Access all files" for an app
-    APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_DENY = 1731;
-
-    // ACTION: Battery feature usage
-    ACTION_BATTERY_OPTION_FEATURE_USAGE = 1732;
-
-    // ACTION: Battery feature runtime event
-    ACTION_BATTERY_OPTION_RUNTIME_EVENT = 1733;
-
-    // ACTION: Settings > Developer Options > Toggle on Wireless debugging
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_ADB_WIRELESS_ON = 1734;
-
-    // ACTION: Settings > Developer Options > Toggle off Wireless debugging
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_ADB_WIRELESS_OFF = 1735;
-
-    // ACTION: Change Wi-Fi hotspot name
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_SETTINGS_CHANGE_WIFI_HOTSPOT_NAME = 1736;
-
-    // ACTION: Change Wi-Fi hotspot password
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_SETTINGS_CHANGE_WIFI_HOTSPOT_PASSWORD = 1737;
-
-    // ACTION: Settings > Security > Toggle on Confirm Sim deletion
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_CONFIRM_SIM_DELETION_ON = 1738;
-
-    // ACTION: Settings > Security > Toggle off Confirm Sim deletion
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACTION_CONFIRM_SIM_DELETION_OFF = 1739;
-
-    // ACTION: Settings > System > Gestures > Double tap > Toggle on Double tap
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_ENABLED = 1740;
-
-    // ACTION: Settings > System > Gestures > Double tap > Toggle off Double tap
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_DISABLED = 1741;
-
-    // ACTION: Settings > System > Gestures > Double tap > Invoke Assistant
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_ACTION_ASSISTANT = 1742;
-
-    // ACTION: Settings > System > Gestures > Double tap > Take screenshot
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_ACTION_SCREENSHOT = 1743;
-
-    // ACTION: Settings > System > Gestures > Double tap > Play and pause
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_ACTION_PLAY_PAUSE = 1744;
-
-    // ACTION: Settings > System > Gestures > Double tap > Open app overview
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_ACTION_OVERVIEW = 1745;
-
-    // ACTION: Settings > System > Gestures > Double tap > Open notification shade
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_ACTION_NOTIFICATION_SHADE = 1746;
-
-    // ACTION: Settings > System > Gestures > Double tap > Require harder taps
-    // CATEGORY: SETTINGS
-    // OS: S
-    ACTION_COLUMBUS_LOW_SENSITIVITY = 1747;
-
-    // OPEN: Columbus Gesture training intro in Settings
-    // CATEGORY: SETTINGS
-    // OS: S
-    SETTINGS_COLUMBUS_GESTURE_TRAINING_INTRO = 1748;
-
-    // OPEN: Columbus Gesture training enrolling in Settings
-    // CATEGORY: SETTINGS
-    // OS: S
-    SETTINGS_COLUMBUS_GESTURE_TRAINING_ENROLLING = 1749;
-
-    // OPEN: Columbus Gesture training finished in Settings
-    // CATEGORY: SETTINGS
-    // OS: S
-    SETTINGS_COLUMBUS_GESTURE_TRAINING_FINISHED = 1750;
-}
-
-/**
- * Id for Settings pages. Each page must have its own unique Id.
- */
-enum PageId {
-    // Unknown page. Should not be used in production code.
-    PAGE_UNKNOWN = 0;
-
-    // OPEN: Settings > Accessibility
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCESSIBILITY = 2;
-
-    // OPEN: Settings > Accessibility > Captions preference
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCESSIBILITY_CAPTION_PROPERTIES = 3;
-
-    // OPEN: Settings > Accessibility > [Service]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCESSIBILITY_SERVICE = 4;
-
-    // OPEN: Settings > Accessibility > Color correction
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
-
-    // OPEN: Settings > Accessibility > Accessibility shortcut
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
-
-    // OPEN: Settings > Accessibility > Magnification gestures (Renamed in O)
-    // OPEN: Settings > Accessibility > Magnification > Magnify with triple-tap
-    // OPEN: Settings > Accessibility > Magnification > Magnify with button
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
-
-    // OPEN: Settings > Accounts
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCOUNT = 8;
-
-    // OPEN: Settings > Accounts > [Single Account Sync Settings]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCOUNTS_ACCOUNT_SYNC = 9;
-
-    // OPEN: Settings > Accounts > Add an account
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
-
-    // OPEN: Settings > Cellular network settings > APNs
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APN = 12;
-
-    // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APN_EDITOR = 13;
-
-    // OPEN: Settings > Apps > Configure apps > App links > [App]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_APP_LAUNCH = 17;
-
-    // OPEN: Settings > Internal storage > Apps storage > [App]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_APP_STORAGE = 19;
-
-    // OPEN: Settings > Apps > [App info]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_INSTALLED_APP_DETAILS = 20;
-
-    // OPEN: Settings > Memory > App usage > [App Memory usage]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_PROCESS_STATS_DETAIL = 21;
-
-    // OPEN: Settings > Memory > App usage
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_PROCESS_STATS_UI = 23;
-
-    // OPEN: Choose Bluetooth device (ex: when sharing)
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    BLUETOOTH_DEVICE_PICKER = 25;
-
-    // OPEN: Settings > Security > Choose screen lock
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    CHOOSE_LOCK_GENERIC = 27;
-
-    // OPEN: Settings > Security > Choose screen lock > Choose your password
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    CHOOSE_LOCK_PASSWORD = 28;
-
-    // OPEN: Settings > Security > Choose screen lock > Choose your pattern
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    CHOOSE_LOCK_PATTERN = 29;
-
-    // OPEN: Settings > Security > Choose screen lock > Confirm your password
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    CONFIRM_LOCK_PASSWORD = 30;
-
-    // OPEN: Settings > Security > Choose screen lock > Confirm your pattern
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    CONFIRM_LOCK_PATTERN = 31;
-
-    // OPEN: Settings > Security > Encrypt phone
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    CRYPT_KEEPER = 32;
-
-    // OPEN: Settings > Security > Encrypt phone > Confirm
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    CRYPT_KEEPER_CONFIRM = 33;
-
-    // OPEN: Settings (Root page)
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DASHBOARD_SUMMARY = 35;
-
-    // OPEN: Settings > Data usage
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DATA_USAGE_SUMMARY = 37;
-
-    // OPEN: Settings > Date & time
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DATE_TIME = 38;
-
-    // OPEN: Settings > Developer options
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DEVELOPMENT = 39;
-
-    // OPEN: Settings > About phone
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DEVICEINFO = 40;
-
-    // OPEN: Settings > Internal storage
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DEVICEINFO_STORAGE = 42;
-
-    // OPEN: Settings > Display
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DISPLAY = 46;
-
-    // OPEN: Settings > Display > Daydream
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    DREAM = 47;
-
-    // OPEN: Settings > Security > Screen lock > Secure start-up
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ENCRYPTION = 48;
-
-    // OPEN: Settings > Security > Nexus Imprint
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT = 49;
-
-    // OPEN: Settings > Battery > History details
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
-
-    // OPEN: Settings > Battery > Battery saver
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FUELGAUGE_BATTERY_SAVER = 52;
-
-    // OPEN: Settings > Battery > [App Use details]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FUELGAUGE_POWER_USAGE_DETAIL = 53;
-
-    // OPEN: Settings > Security > SIM card lock settings
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ICC_LOCK = 56;
-
-    // OPEN: Settings > Language & input > Physical keyboard
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    INPUTMETHOD_KEYBOARD = 58;
-
-    // OPEN: Settings > Language & input > Spell checker
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    INPUTMETHOD_SPELL_CHECKERS = 59;
-
-    // OBSOLETE
-    INPUTMETHOD_SUBTYPE_ENABLER = 60;
-
-    // OPEN: Settings > Language & input > Personal dictionary
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    INPUTMETHOD_USER_DICTIONARY = 61;
-
-    // OPEN: Settings > Language & input > Add word
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
-
-    // OPEN: Settings > Location
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    LOCATION = 63;
-
-    // OPEN: Settings > Apps
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    MANAGE_APPLICATIONS = 65;
-
-    // OPEN: Settings > Backup & reset > Factory data reset
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    MASTER_CLEAR = 66;
-
-    // OPEN: Settings > Backup & reset > Factory data reset > Confirm
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    MASTER_CLEAR_CONFIRM = 67;
-
-    // OPEN: Settings > More > Android Beam
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NFC_BEAM = 69;
-
-    // OPEN: Settings > Tap & pay
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NFC_PAYMENT = 70;
-
-    // OPEN: Settings > Sound & notification > App notifications > [App]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_APP_NOTIFICATION = 72;
-
-    // OBSOLETE
-    NOTIFICATION_REDACTION = 74;
-
-    // OPEN: Settings Widget > Notification log
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_STATION = 75;
-
-    // OPEN: Settings > Sound & notification > Do not disturb
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_ZEN_MODE = 76;
-
-
-    // OPEN: Print job notification > Print job settings
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    PRINT_JOB_SETTINGS = 78;
-
-    // OPEN: Settings > Printing > [Print Service]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    PRINT_SERVICE_SETTINGS = 79;
-
-    // OPEN: Settings > Printing
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    PRINT_SETTINGS = 80;
-
-    // OPEN: Settings > Backup & reset
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    PRIVACY = 81;
-
-    //OBSOLETE
-    PROXY_SELECTOR = 82;
-
-    // OPEN: Settings > Backup & reset > Network settings reset
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    RESET_NETWORK = 83;
-
-    // OPEN: Settings > Backup & reset > Network settings reset > Confirm
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    RESET_NETWORK_CONFIRM = 84;
-
-    // OPEN: Settings > Developer Options > Running Services
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    RUNNING_SERVICE_DETAILS = 85;
-
-    // OPEN: Settings > Security > Screen pinning
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    SCREEN_PINNING = 86;
-
-    // OPEN: Settings > Security
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    SECURITY = 87;
-
-    // OPEN: Settings > SIM cards
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    SIM = 88;
-
-    // OBSOLETE
-    TESTING = 89;
-
-    // OPEN: Settings > More > Tethering & portable hotspot
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    TETHER = 90;
-
-    // OPEN: Settings > Security > Trust agents
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    TRUST_AGENT = 91;
-
-    // OPEN: Settings > Security > Trusted credentials
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    TRUSTED_CREDENTIALS = 92;
-
-    // OPEN: Settings > Language & input > TTS output > [Engine] > Settings
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    TTS_ENGINE_SETTINGS = 93;
-
-    // OPEN: Settings > Language & input > Text-to-speech output
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    TTS_TEXT_TO_SPEECH = 94;
-
-    // OPEN: Settings > Security > Apps with usage access
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    USAGE_ACCESS = 95;
-
-    // OPEN: Settings > Users
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    USER = 96;
-
-    // OPEN: Settings > Users > [Restricted profile app & content access]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    USERS_APP_RESTRICTIONS = 97;
-
-    // OPEN: Settings > Users > [User settings]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    USER_DETAILS = 98;
-
-    // OPEN: Settings > More > VPN
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    VPN = 100;
-
-    // OPEN: Settings > Display > Choose wallpaper from
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    WALLPAPER_TYPE = 101;
-
-    // OPEN: Settings > Display > Cast
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    WFD_WIFI_DISPLAY = 102;
-
-    // OPEN: Settings > Wi-Fi
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    WIFI = 103;
-
-    // OPEN: Settings > More > Wi-Fi Calling
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    WIFI_CALLING = 105;
-
-    // OPEN: Settings > Wi-Fi > Saved networks
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    WIFI_SAVED_ACCESS_POINTS = 106;
-
-    // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    WIFI_P2P = 109;
-
-    // OPEN: Settings > Apps > Configure apps > App permissions
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_ADVANCED = 130;
-
-    // OPEN: Settings > Location > Scanning
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    LOCATION_SCANNING = 131;
-
-    // OPEN: Settings > Sound & notification > App notifications
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
-
-    // OPEN: Settings > Sound & notification > DND > Priority only allows
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_ZEN_MODE_PRIORITY = 141;
-
-    // OPEN: Settings > Sound & notification > DND > Automatic rules
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
-
-    // OPEN: Settings > Sound & notification > DND > [Time based rule]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
-
-    // OPEN: Settings > Apps > Configure apps > App links
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    MANAGE_DOMAIN_URLS = 143;
-
-    // OPEN: Settings > Sound & notification > DND > [Event rule]
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
-
-    // OPEN: Settings > Sound & notification > Notification access
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_ACCESS = 179;
-
-    // OPEN: Settings > Sound & notification > Do Not Disturb access
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    NOTIFICATION_ZEN_MODE_ACCESS = 180;
-
-    // OPEN: Settings > Internal storage > Apps storage
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_STORAGE_APPS = 182;
-
-    // OPEN: Settings > Security > Usage access
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
-
-    // OPEN: Settings > Battery > Battery optimization
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_HIGH_POWER_APPS = 184;
-
-    // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    APPLICATIONS_MANAGE_ASSIST = 201;
-
-    // OPEN: Settings > Memory
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    PROCESS_STATS_SUMMARY = 202;
-
-    // OPEN: Settings > Apps > Configure Apps > Display over other apps
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    SYSTEM_ALERT_WINDOW_APPS = 221;
-
-    // OPEN: Settings > About phone > Legal information
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    ABOUT_LEGAL_SETTINGS = 225;
-
-
-    // OPEN: Settings > Developer options > Inactive apps
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FUELGAUGE_INACTIVE_APPS = 238;
-
-    // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_ENROLLING = 240;
-    // OPEN: Fingerprint Enroll > Find Sensor
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_FIND_SENSOR = 241;
-
-    // OPEN: Fingerprint Enroll > Fingerprint Enrolled!
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_ENROLL_FINISH = 242;
-
-    // OPEN: Fingerprint Enroll introduction
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_ENROLL_INTRO = 243;
-
-    // OPEN: Fingerprint Enroll > Let's Start!
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_ENROLL_SIDECAR = 245;
-
-    // OPEN: Fingerprint Enroll SUW > Let's Start!
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_ENROLLING_SETUP = 246;
-
-    // OPEN: Fingerprint Enroll SUW > Find Sensor
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_FIND_SENSOR_SETUP = 247;
-
-    // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled!
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_ENROLL_FINISH_SETUP = 248;
-
-    // OPEN: Fingerprint Enroll SUW introduction
-    // CATEGORY: SETTINGS
-    // OS: 6.0
-    FINGERPRINT_ENROLL_INTRO_SETUP = 249;
-
-    // OPEN: Settings > Developer Options > Background Check
-    // CATEGORY: SETTINGS
-    // OS: N
-    BACKGROUND_CHECK_SUMMARY = 258;
-
-    // OPEN: Settings > Notifications > [App] > Channel Notifications
-    // CATEGORY: SETTINGS
-    // OS: N
-    NOTIFICATION_TOPIC_NOTIFICATION = 265;
-
-    // OPEN: Settings > Security > User credentials
-    // CATEGORY: Settings
-    // OS: N
-    USER_CREDENTIALS = 285;
-
-    // Logs that the user has edited the enabled VR listeners.
-    // CATEGORY: SETTINGS
-    // OS: N
-    VR_MANAGE_LISTENERS = 334;
-
-    // Settings -> Accessibility -> Click after pointer stops moving
-    // CATEGORY: SETTINGS
-    // OS: N
-    ACCESSIBILITY_TOGGLE_AUTOCLICK = 335;
-
-    // Settings -> Sound
-    // CATEGORY: SETTINGS
-    // OS: N
-    SOUND = 336;
-
-    // Settings -> Notifications -> Gear
-    // CATEGORY: SETTINGS
-    // OS: N
-    CONFIGURE_NOTIFICATION = 337;
-
-    // Settings -> Wi-Fi -> Gear
-    // CATEGORY: SETTINGS
-    // OS: N
-    CONFIGURE_WIFI = 338;
-
-    // Settings -> Display -> Display size
-    // OS: N
-    DISPLAY_SCREEN_ZOOM = 339;
-
-    // Settings -> Display -> Font size
-    // CATEGORY: SETTINGS
-    // OS: N
-    ACCESSIBILITY_FONT_SIZE = 340;
-
-    // Settings -> Data usage -> Cellular/Wi-Fi data usage
-    // CATEGORY: SETTINGS
-    // OS: N
-    DATA_USAGE_LIST = 341;
-
-    // Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear
-    // CATEGORY: SETTINGS
-    // OS: N
-    BILLING_CYCLE = 342;
-
-    // DATA_USAGE_LIST -> Any item or App info -> Data usage
-    // CATEGORY: SETTINGS
-    // OS: N
-    APP_DATA_USAGE = 343;
-
-    // Settings -> Language & input -> Language
-    // CATEGORY: SETTINGS
-    // OS: N
-    USER_LOCALE_LIST = 344;
-
-    // Settings -> Language & input -> Virtual keyboard
-    // CATEGORY: SETTINGS
-    // OS: N
-    VIRTUAL_KEYBOARDS = 345;
-
-    // Settings -> Language & input -> Physical keyboard
-    // CATEGORY: SETTINGS
-    // OS: N
-    PHYSICAL_KEYBOARDS = 346;
-
-    // Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard
-    // CATEGORY: SETTINGS
-    // OS: N
-    ENABLE_VIRTUAL_KEYBOARDS = 347;
-
-    // Settings -> Data usage -> Data Saver
-    // CATEGORY: SETTINGS
-    // OS: N
-    DATA_SAVER_SUMMARY = 348;
-
-    // Settings -> Data usage -> Data Saver -> Unrestricted data access
-    // CATEGORY: SETTINGS
-    // OS: N
-    DATA_USAGE_UNRESTRICTED_ACCESS = 349;
-
-    // Settings -> Apps -> Gear -> Special access
-    SPECIAL_ACCESS = 351;
-
-    // OPEN: SUW Welcome Screen -> Vision Settings
-    // CATEGORY: SETTINGS
-    // OS: N
-    SUW_ACCESSIBILITY = 367;
-
-    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification gestures (Renamed in O)
-    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with triple-tap
-    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with button
-    // ACTION: New magnification gesture configuration is chosen
-    //  SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: N
-    SUW_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 368;
-
-    // OPEN: SUW Welcome Screen -> Vision Settings -> Font size
-    // ACTION: New font size is chosen
-    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is largest
-    // CATEGORY: SETTINGS
-    // OS: N
-    SUW_ACCESSIBILITY_FONT_SIZE = 369;
-
-    // OPEN: SUW Welcome Screen -> Vision Settings -> Display size
-    // ACTION: New display size is chosen
-    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is larger, 4 is largest
-    // CATEGORY: SETTINGS
-    // OS: N
-    SUW_ACCESSIBILITY_DISPLAY_SIZE = 370;
-
-    // OPEN: SUW Welcome Screen -> Vision Settings -> TalkBack
-    // ACTION: New screen reader configuration is chosen
-    //  SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: N
-    SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER = 371;
-
-    // Airplane mode on
-    SETTINGS_CONDITION_AIRPLANE_MODE = 377;
-    // AKA Data saver on
-    SETTINGS_CONDITION_BACKGROUND_DATA = 378;
-    // Battery saver on
-    SETTINGS_CONDITION_BATTERY_SAVER = 379;
-    // Cellular data off
-    SETTINGS_CONDITION_CELLULAR_DATA = 380;
-    // Do not disturb on
-    SETTINGS_CONDITION_DND = 381;
-    // Hotspot on
-    SETTINGS_CONDITION_HOTSPOT = 382;
-    // Work profile off
-    SETTINGS_CONDITION_WORK_MODE = 383;
-
-    // Settings > Apps > Gear > Special Access > Premium SMS access
-    PREMIUM_SMS_ACCESS = 388;
-
-    // OPEN: Settings > Accounts > Work profile settings
-    // CATEGORY: SETTINGS
-    ACCOUNTS_WORK_PROFILE_SETTINGS = 401;
-
-    // Settings -> Dev options -> Convert to file encryption
-    CONVERT_FBE = 402;
-
-    // Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT...
-    CONVERT_FBE_CONFIRM = 403;
-
-    // Settings -> Dev options -> Running services
-    RUNNING_SERVICES = 404;
-
-    // The dialog shown by 3P intent to change current webview implementation.
-    WEBVIEW_IMPLEMENTATION = 405;
-
-    // OPEN: Settings > Internal storage > Storage manager
-    // CATEGORY: SETTINGS
-    STORAGE_MANAGER_SETTINGS = 458;
-
-    // OPEN: Settings -> Gestures
-    // CATEGORY: SETTINGS
-    SETTINGS_GESTURES = 459;
-
-    // OPEN: Settings > Display > Night Light
-    // CATEGORY: SETTINGS
-    NIGHT_DISPLAY_SETTINGS = 488;
-
-    // Night Light on
-    SETTINGS_CONDITION_NIGHT_DISPLAY = 492;
-
-    // OPEN: Settings > Language & input > Personal dictionary (single locale)
-    USER_DICTIONARY_SETTINGS = 514;
-
-    // OPEN: Settings > Date & time > Select time zone
-    ZONE_PICKER = 515;
-
-    // OPEN: Settings > Security > Device administrators
-    DEVICE_ADMIN_SETTINGS = 516;
-
-    // OPEN: Settings > Security > Factory Reset Protection dialog
-    DIALOG_FRP = 528;
-
-    // OPEN: Settings > Custom list preference with confirmation message
-    DIALOG_CUSTOM_LIST_CONFIRMATION = 529;
-
-    // OPEN: Settings > APN Editor > Error dialog
-    DIALOG_APN_EDITOR_ERROR = 530;
-
-    // OPEN: Settings > Users > Edit owner info dialog
-    DIALOG_OWNER_INFO_SETTINGS = 531;
-
-    // OPEN: Settings > Security > Use one lock dialog
-    DIALOG_UNIFICATION_CONFIRMATION = 532;
-
-    // OPEN: Settings > Security > User Credential
-    DIALOG_USER_CREDENTIAL = 533;
-
-    // OPEN: Settings > Accounts > Remove account
-    DIALOG_REMOVE_USER = 534;
-
-    // OPEN: Settings > Accounts > Confirm auto sync dialog
-    DIALOG_CONFIRM_AUTO_SYNC_CHANGE = 535;
-
-    // OPEN: Settings > Apps > Dialog for running service details
-    DIALOG_RUNNIGN_SERVICE = 536;
-
-    // OPEN: Settings > Bluetooth > Rename this device
-    DIALOG_BLUETOOTH_RENAME = 538;
-
-    // OPEN: Settings > Battery optimization > details for app
-    DIALOG_HIGH_POWER_DETAILS = 540;
-
-    // OPEN: Settings > Keyboard > Show keyboard layout dialog
-    DIALOG_KEYBOARD_LAYOUT = 541;
-
-    // OPEN: Settings > WIFI Scan permission dialog
-    DIALOG_WIFI_SCAN_MODE = 543;
-
-    // OPEN: Settings > Wireless > VPN > Config dialog
-    DIALOG_LEGACY_VPN_CONFIG = 545;
-
-    // OPEN: Settings > Wireless > VPN > Config dialog for app
-    DIALOG_VPN_APP_CONFIG = 546;
-
-    // OPEN: Settings > Wireless > VPN > Cannot connect dialog
-    DIALOG_VPN_CANNOT_CONNECT = 547;
-
-    // OPEN: Settings > Wireless > VPN > Replace existing VPN dialog
-    DIALOG_VPN_REPLACE_EXISTING = 548;
-
-    // OPEN: Settings > Billing cycle > Edit billing cycle dates dialog
-    DIALOG_BILLING_CYCLE = 549;
-
-    // OPEN: Settings > Billing cycle > Edit data limit/warning dialog
-    DIALOG_BILLING_BYTE_LIMIT = 550;
-
-    // OPEN: Settings > Billing cycle > turn on data limit dialog
-    DIALOG_BILLING_CONFIRM_LIMIT = 551;
-
-    // OPEN: Settings > Service > Turn off notification access dialog
-    DIALOG_DISABLE_NOTIFICATION_ACCESS = 552;
-
-    // OPEN: Settings > Sound > Use personal sound for work profile dialog
-    DIALOG_UNIFY_SOUND_SETTINGS = 553;
-
-    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being granted.
-    DIALOG_ZEN_ACCESS_GRANT = 554;
-
-    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being revoked.
-    DIALOG_ZEN_ACCESS_REVOKE = 555;
-
-    // OPEN: Settings > Zen mode > Dialog that picks time for zen mode.
-    DIALOG_ZEN_TIMEPICKER = 556;
-
-    // OPEN: Settings > Apps > Dialog that informs user to allow service access for app.
-    DIALOG_SERVICE_ACCESS_WARNING = 557;
-
-    // OPEN: Settings > Apps > Dialog for app actions (such as force stop/clear data)
-    DIALOG_APP_INFO_ACTION = 558;
-
-    // OPEN: Settings > Storage > Dialog for forgetting a storage device
-    DIALOG_VOLUME_FORGET = 559;
-
-    // OPEN: Settings > Storage > Dialog for initializing a volume
-    DIALOG_VOLUME_INIT = 561;
-
-    // OPEN: Settings > Storage > Dialog for unmounting a volume
-    DIALOG_VOLUME_UNMOUNT = 562;
-
-    // OPEN: Settings > Storage > Dialog for renaming a volume
-    DIALOG_VOLUME_RENAME = 563;
-
-    // OPEN: Settings > Storage > Dialog for clear cache
-    DIALOG_STORAGE_CLEAR_CACHE = 564;
-
-    // OPEN: Settings > Storage > Dialog for system info
-    DIALOG_STORAGE_SYSTEM_INFO = 565;
-
-    // OPEN: Settings > Storage > Dialog for other info
-    DIALOG_STORAGE_OTHER_INFO = 566;
-
-    // OPEN: Settings > Storage > Dialog for user info
-    DIALOG_STORAGE_USER_INFO = 567;
-    // OPEN: Settings > Add fingerprint > Dialog when user touches fingerprint icon.
-    DIALOG_FINGERPRINT_ICON_TOUCH = 568;
-
-    // OPEN: Settings > Add fingerprint > Error dialog
-    DIALOG_FINGERPINT_ERROR = 569;
-
-    // OPEN: Settings > Fingerprint > Rename or delete dialog
-    DIALOG_FINGERPINT_EDIT = 570;
-
-    // OPEN: Settings > Fingerprint > Dialog for deleting last fingerprint
-    DIALOG_FINGERPINT_DELETE_LAST = 571;
-
-    // OPEN: SUW > Fingerprint > Dialog to confirm skip fingerprint setup entirely.
-    DIALOG_FINGERPRINT_SKIP_SETUP = 573;
-
-    // OPEN: Settings > Proxy Selector error dialog
-    DIALOG_PROXY_SELECTOR_ERROR = 574;
-
-    // OPEN: Settings > Wifi > P2P Settings > Disconnect dialog
-    DIALOG_WIFI_P2P_DISCONNECT = 575;
-
-    // OPEN: Settings > Wifi > P2P Settings > Cancel connection dialog
-    DIALOG_WIFI_P2P_CANCEL_CONNECT = 576;
-
-    // OPEN: Settings > Wifi > P2P Settings > Rename dialog
-    DIALOG_WIFI_P2P_RENAME = 577;
-
-    // OPEN: Settings > Wifi > P2P Settings > Forget group dialog
-    DIALOG_WIFI_P2P_DELETE_GROUP = 578;
-
-    // OPEN: Settings > APN > Restore default dialog
-    DIALOG_APN_RESTORE_DEFAULT = 579;
-
-    // OPEN: Settings > Encryption interstitial accessibility warning dialog
-    DIALOG_ENCRYPTION_INTERSTITIAL_ACCESSIBILITY = 581;
-
-    // OPEN: Settings > Acessibility > Enable accessiblity service dialog
-    DIALOG_ACCESSIBILITY_SERVICE_ENABLE = 583;
-
-    // OPEN: Settings > Acessibility > Disable accessiblity service dialog
-    DIALOG_ACCESSIBILITY_SERVICE_DISABLE = 584;
-
-    // OPEN: Settings > Account > Remove account dialog
-    DIALOG_ACCOUNT_SYNC_REMOVE = 585;
-
-    // OPEN: Settings > Account > Remove account failed dialog
-    DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL = 586;
-
-    // OPEN: Settings > Account > Cannot do onetime sync dialog
-    DIALOG_ACCOUNT_SYNC_CANNOT_ONETIME_SYNC = 587;
-
-    // OPEN: Settings > Display > Night light > Set start time dialog
-    DIALOG_NIGHT_DISPLAY_SET_START_TIME = 588;
-
-    // OPEN: Settings > Display > Night light > Set end time dialog
-    DIALOG_NIGHT_DISPLAY_SET_END_TIME = 589;
-
-
-
-        // OPEN: Settings > User > Edit info dialog
-        DIALOG_USER_EDIT = 590;
-
-        // OPEN: Settings > User > Confirm remove dialog
-        DIALOG_USER_REMOVE = 591;
-
-        // OPEN: Settings > User > Enable calling dialog
-        DIALOG_USER_ENABLE_CALLING = 592;
-
-        // OPEN: Settings > User > Enable calling and sms dialog
-        DIALOG_USER_ENABLE_CALLING_AND_SMS = 593;
-
-        // OPEN: Settings > User > Cannot manage device message dialog
-        DIALOG_USER_CANNOT_MANAGE = 594;
-
-        // OPEN: Settings > User > Add user dialog
-        DIALOG_USER_ADD = 595;
-
-        // OPEN: Settings > User > Setup user dialog
-        DIALOG_USER_SETUP = 596;
-
-        // OPEN: Settings > User > Setup profile dialog
-        DIALOG_USER_SETUP_PROFILE = 597;
-
-        // OPEN: Settings > User > Choose user type dialog
-        DIALOG_USER_CHOOSE_TYPE = 598;
-
-        // OPEN: Settings > User > Need lockscreen dialog
-        DIALOG_USER_NEED_LOCKSCREEN = 599;
-
-        // OPEN: Settings > User > Confirm exit guest mode dialog
-        DIALOG_USER_CONFIRM_EXIT_GUEST = 600;
-
-        // OPEN: Settings > User > Edit user profile dialog
-        DIALOG_USER_EDIT_PROFILE = 601;
-
-
-    // OPEN: Settings > Wifi > Saved AP > Edit dialog
-    DIALOG_WIFI_SAVED_AP_EDIT = 602;
-
-    // OPEN: Settings > Wifi > Edit AP dialog
-    DIALOG_WIFI_AP_EDIT = 603;
-
-    // OPEN: Settings > Wifi > Write config to NFC dialog
-    DIALOG_WIFI_WRITE_NFC = 606;
-
-    // OPEN: Settings > Date > Date picker dialog
-    DIALOG_DATE_PICKER = 607;
-
-    // OPEN: Settings > Date > Time picker dialog
-    DIALOG_TIME_PICKER = 608;
-
-    // OPEN: Settings > Wireless > Manage wireless plan dialog
-    DIALOG_MANAGE_MOBILE_PLAN = 609;
-
-    // OPEN Settings > Bluetooth > Attempt to connect to device that shows dialog
-    BLUETOOTH_DIALOG_FRAGMENT = 613;
-
-    // OPEN: Settings > Security
-    // CATEGORY: SETTINGS
-    // OS: O
-    ENTERPRISE_PRIVACY_SETTINGS = 628;
-
-    // OPEN: Settings > System
-    SETTINGS_SYSTEM_CATEGORY = 744;
-
-    // OPEN: Settings > Storage
-    SETTINGS_STORAGE_CATEGORY = 745;
-
-    // OPEN: Settings > Network & Internet
-    SETTINGS_NETWORK_CATEGORY = 746;
-
-    // OPEN: Settings > Connected Device
-    SETTINGS_CONNECTED_DEVICE_CATEGORY = 747;
-
-    // OPEN: Settings > App & Notification
-    SETTINGS_APP_NOTIF_CATEGORY = 748;
-
-    // OPEN: Settings > System > Language & Region
-    SETTINGS_LANGUAGE_CATEGORY = 750;
-
-    // OPEN: Settings > System > Input & Gesture > Swipe fingerprint for notifications
-    SETTINGS_GESTURE_SWIPE_TO_NOTIFICATION = 751;
-
-    // OPEN: Settings > System > Input & Gesture > Double tap power button gesture
-    SETTINGS_GESTURE_DOUBLE_TAP_POWER = 752;
-
-    // OPEN: Settings > System > Input & Gesture > Pick up gesture
-    SETTINGS_GESTURE_PICKUP = 753;
-
-    // OPEN: Settings > System > Input & Gesture > Double tap screen gesture
-    SETTINGS_GESTURE_DOUBLE_TAP_SCREEN = 754;
-
-    // OPEN: Settings > System > Input & Gesture > Double twist gesture
-    SETTINGS_GESTURE_DOUBLE_TWIST = 755;
-
-    // OPEN: Settings > Apps > Default Apps > Default browser
-    DEFAULT_BROWSER_PICKER = 785;
-    // OPEN: Settings > Apps > Default Apps > Default emergency app
-    DEFAULT_EMERGENCY_APP_PICKER = 786;
-
-    // OPEN: Settings > Apps > Default Apps > Default home
-    DEFAULT_HOME_PICKER = 787;
-
-    // OPEN: Settings > Apps > Default Apps > Default phone
-    DEFAULT_PHONE_PICKER = 788;
-
-    // OPEN: Settings > Apps > Default Apps > Default sms
-    DEFAULT_SMS_PICKER = 789;
-
-    // OPEN: Settings > Apps > Notification > Notification Assistant
-    DEFAULT_NOTIFICATION_ASSISTANT = 790;
-
-
-    // OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
-    DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
-
-    // OPEN: Settings > Apps > Default Apps > Default autofill app
-    DEFAULT_AUTOFILL_PICKER = 792;
-
-    // OPEN: Settings > Apps > Gear > Special Access > Install other apps
-    // CATEGORY: SETTINGS
-    // OS: 8.0
-    MANAGE_EXTERNAL_SOURCES = 808;
-
-    // Logs that the user has edited the picture-in-picture settings.
-    // CATEGORY: SETTINGS
-    SETTINGS_MANAGE_PICTURE_IN_PICTURE = 812;
-
-    // OPEN: SUW Welcome Screen -> Vision Settings -> Select to Speak
-    // ACTION: Select to Speak configuration is chosen
-    //  SUBTYPE: 0 is off, 1 is on
-    // CATEGORY: SETTINGS
-    // OS: N
-    SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK = 817;
-
-    // OPEN: Settings > System > Backup
-    // CATEGORY: SETTINGS
-    // OS: O
-    BACKUP_SETTINGS = 818;
-
-    // OPEN: Settings > Storage > Games
-    // CATEGORY: SETTINGS
-    // OS: O
-    APPLICATIONS_STORAGE_GAMES = 838;
-
-    // OPEN: Settings > Storage > Audio and Music
-    // CATEGORY: SETTINGS
-    // OS: O
-    APPLICATIONS_STORAGE_MUSIC = 839;
-
-    // ACTION: Settings > Storage > Free Up Space to launch Deletion Helper
-    // CATEGORY: SETTINGS
-    // OS: O
-    STORAGE_FREE_UP_SPACE_NOW = 840;
-
-    // ACTION: Settings > Storage > Files to open the File Manager
-    // CATEGORY: SETTINGS
-    // OS: O
-    STORAGE_FILES = 841;
-
-    // OPEN: Settings > Apps > Default Apps > Assist >  Default assist
-    DEFAULT_ASSIST_PICKER = 843;
-
-    // OPEN: Settings > Apps > Default Apps > Assist >  Default voice input
-    DEFAULT_VOICE_INPUT_PICKER = 844;
-
-    // OPEN: Settings > Storage > [Profile]
-    SETTINGS_STORAGE_PROFILE = 845;
-
-    // OPEN: Settings > Security & screen lock -> Encryption & crendentials
-    // CATEGORY: SETTINGS
-    // OS: O
-    ENCRYPTION_AND_CREDENTIAL = 846;
-
-    // OPEN: Settings > Wi-Fi > Network Details (click on Access Point)
-    // CATEGORY: SETTINGS
-    // OS: O
-    WIFI_NETWORK_DETAILS = 849;
-
-    // OPEN: Settings > Wi-Fi > Wifi Preferences -> Advanced -> Network Scorer
-    // CATEGORY: SETTINGS
-    // OS: O
-    SETTINGS_NETWORK_SCORER = 861;
-
-    // OPEN: Settings > About device > Model > Hardware info dialog
-    DIALOG_SETTINGS_HARDWARE_INFO = 862;
-
-    // OPEN: Settings > Security & screen lock -> Lock screen preferences
-    // CATEGORY: SETTINGS
-    SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
-
-
-    // OPEN: Settings -> Display -> When in VR Mode
-    VR_DISPLAY_PREFERENCE = 921;
-
-    // OPEN: Settings > Accessibility > Magnification
-    // CATEGORY: SETTINGS
-    // OS: O
-    ACCESSIBILITY_SCREEN_MAGNIFICATION_SETTINGS = 922;
-
-    // OPEN: Settings -> System -> Reset options
-    RESET_DASHBOARD = 924;
-
-     // OPEN: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
-    // CATEGORY: SETTINGS
-    // OS: O
-    FINGERPRINT_REMOVE_SIDECAR = 934;
-
-    // OPEN: Settings > Storage > Movies & TV
-    // CATEGORY: SETTINGS
-    // OS: O
-    APPLICATIONS_STORAGE_MOVIES = 935;
-
-    // OPEN: Settings > Security > Managed Device Info > Apps installed
-    // CATEGORY: SETTINGS
-    // OS: O
-    ENTERPRISE_PRIVACY_INSTALLED_APPS = 938;
-
-    // OPEN: Settings > Security > Managed Device Info > nnn permissions
-    // CATEGORY: SETTINGS
-    // OS: O
-    ENTERPRISE_PRIVACY_PERMISSIONS = 939;
-
-
-    // OPEN: Settings > Security > Managed Device Info > Default apps
-    // CATEGORY: SETTINGS
-    // OS: O
-    ENTERPRISE_PRIVACY_DEFAULT_APPS = 940;
-
-    // OPEN: Choose screen lock dialog in Settings
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    SETTINGS_CHOOSE_LOCK_DIALOG = 990;
-
-    // OPEN: Settings > System > Languages & input > Assist gesture
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    SETTINGS_ASSIST_GESTURE = 996;
-
-    // OPEN: Settings > Connected Devices > Bluetooth > (click on details link for a paired device)
-    BLUETOOTH_DEVICE_DETAILS = 1009;
-
-    // OPEN: Settings > credential pages - prompt for key guard configuration confirmation
-    CONFIGURE_KEYGUARD_DIALOG = 1010;
-
-    // OPEN: Settings > Network > Tether > Wi-Fi hotspot
-    WIFI_TETHER_SETTINGS = 1014;
-
-    // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device)
-    // -> Edit name button.
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    DIALOG_BLUETOOTH_PAIRED_DEVICE_RENAME = 1015;
-
-    // OPEN: Settings > Connected devices > Bluetooth > Pair new device
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    BLUETOOTH_PAIRING = 1018;
-
-    // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device)
-    // -> Forget button.
-    // CATEGORY: SETTINGS
-    // OS: O DR
-    DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031;
-
-    // OPEN: Settings > Storage > Photos & Videos
-    // CATEGORY: SETTINGS
-    // OS: O MR
-    APPLICATIONS_STORAGE_PHOTOS = 1092;
-
-    // OPEN: Settings > Display > Colors
-    // CATEGORY: SETTINGS
-    // OS: O MR
-    COLOR_MODE_SETTINGS = 1143;
-
-    // OPEN: Settings > Developer Options > Experiment dashboard
-    // CATEGORY: SETTINGS
-    SETTINGS_FEATURE_FLAGS_DASHBOARD = 1217;
-
-    // OPEN: Settings > Notifications > [App] > Topic Notifications
-    // CATEGORY: SETTINGS
-    // OS: P
-    NOTIFICATION_CHANNEL_GROUP = 1218;
-
-    // OPEN: Settings > Developer options > Enable > Info dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1219;
-
-    // OPEN: Settings > Developer options > OEM unlocking > Info dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_ENABLE_OEM_UNLOCKING = 1220;
-
-    // OPEN: Settings > Developer options > USB debugging > Info dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_ENABLE_ADB = 1222;
-
-    // OPEN: Settings > Security > Nexus Imprint > [Fingerprint]
-    // CATEGORY: SETTINGS
-    // OS: P
-    FINGERPRINT_AUTHENTICATE_SIDECAR = 1221;
-
-    // OPEN: Settings > Developer options > Revoke USB debugging authorizations > Info dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_CLEAR_ADB_KEYS = 1223;
-
-    // Open: Settings > Developer options > Quick setting tile config
-    // CATEGORY: SETTINGS
-    // OS: P
-    DEVELOPMENT_QS_TILE_CONFIG = 1224;
-
-    // OPEN: Settings > Developer options > Store logger data persistently on device > Info dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_LOG_PERSIST = 1225;
-
-    // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
-    // CATEGORY: SETTINGS
-    // OS: P
-    WIFI_CALLING_FOR_SUB = 1230;
-
-    // Open: Settings > Dev options > Oem unlock > lock it > warning dialog.
-    // OS: P
-    DIALOG_OEM_LOCK_INFO = 1238;
-
-    // Open: Settings > System > About phone > IMEI
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_IMEI_INFO = 1240;
-
-    // OPEN: Settings > System > About Phone > Sim status
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_SIM_STATUS = 1246;
-
-    // OPEN: Settings > System > About Phone > Android Version
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_FIRMWARE_VERSION = 1247;
-
-    // OPEN: Settings > Battery(version 2)
-    // CATEGORY: SETTINGS
-    // OS: P
-    FUELGAUGE_POWER_USAGE_SUMMARY_V2 = 1263;
-
-    // OPEN: Settings > Connected devices > Connection preferences
-    // CATEGORY: SETTINGS
-    // OS: P
-    CONNECTION_DEVICE_ADVANCED = 1264;
-
-    // OPEN: Settings > Security > Screen lock gear icon
-    // CATEGORY: SETTINGS
-    // OS: P
-    SCREEN_LOCK_SETTINGS = 1265;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Delete rule (trash can icon)
-    // CATEGORY: SETTINGS
-    // OS: P
-    NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG = 1266;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule > Event/Time
-    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name
-    // CATEGORY: SETTINGS
-    // OS: P
-    NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG = 1269;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule
-    // CATEGORY: SETTINGS
-    // OS: P
-    NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG = 1270;
-
-    // OPEN: Settings > Battery > Smart Battery
-    // CATEGORY: SETTINGS
-    // OS: P
-    FUELGAUGE_SMART_BATTERY = 1281;
-
-    // OPEN: Settings > Battery > Smart Battery > Restricted apps
-    // CATEGORY: SETTINGS
-    // OS: P
-    FUELGAUGE_RESTRICTED_APP_DETAILS = 1285;
-
-    // OPEN: Settings > Sound & notification > Do Not Disturb > Turn on now
-    // CATEGORY: SETTINGS
-    // OS: P
-    NOTIFICATION_ZEN_MODE_ENABLE_DIALOG = 1286;
-
-    // OPEN: Settings->Connected Devices->USB->(click on details link)
-    // CATEGORY: SETTINGS
-    // OS: P
-    USB_DEVICE_DETAILS = 1291;
-
-    // OPEN: Settings > Accessibility > Vibration
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACCESSIBILITY_VIBRATION = 1292;
-
-    // OPEN: Settings > Accessibility > Vibration > Notification vibration
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293;
-
-    // OPEN: Settings > Accessibility > Vibration > Touch vibration
-    // CATEGORY: SETTINGS
-    // OS: P
-    ACCESSIBILITY_VIBRATION_TOUCH = 1294;
-
-    // OPEN: Settings->Developer Options->Default USB
-    // CATEGORY: SETTINGS
-    // OS: P
-    USB_DEFAULT = 1312;
-
-    // OPEN: Settings > Battery > Battery tip > Battery tip Dialog
-    // CATEGORY: SETTINGS
-    // OS: P
-    FUELGAUGE_BATTERY_TIP_DIALOG = 1323;
-
-    // OPEN: DND Settings > What to block
-    // OS: P
-    ZEN_WHAT_TO_BLOCK = 1339;
-
-    // OPEN: Settings > Sounds > Do Not Disturb > Duration
-    // CATEGORY: SETTINGS
-    // OS: P
-    NOTIFICATION_ZEN_MODE_DURATION_DIALOG = 1341;
-
-    // OPEN: Settings > Date & time > Select time zone -> Region
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_ZONE_PICKER_REGION = 1355;
-
-    // OPEN: Settings > Date & time > Select time zone -> Time Zone
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_ZONE_PICKER_TIME_ZONE = 1356;
-    // OPEN: Settings > Date & time > Select time zone -> Select UTC Offset
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357;
-
-    // OPEN: Settings > Gestures > Prevent Ringing
-    // OS: P
-    SETTINGS_PREVENT_RINGING = 1360;
-
-    // Settings > Condition > Device muted
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_CONDITION_DEVICE_MUTED = 1368;
-
-    // Settings > Condition > Device vibrate
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_CONDITION_DEVICE_VIBRATE = 1369;
-
-    // OPEN: Settings > Connected devices > previously connected devices
-    // CATEGORY: SETTINGS
-    // OS: P
-    PREVIOUSLY_CONNECTED_DEVICES = 1370;
-
-    // OPEN: Settings > Network & Internet > Wi-Fi > Wi-Fi Preferences > Turn on Wi-Fi automatically
-    //       note: Wifi Scanning must be off for this dialog to show
-    // CATEGORY: SETTINGS
-    // OS: P
-    WIFI_SCANNING_NEEDED_DIALOG = 1373;
-
-    // OPEN: Settings > System > Gestures > System navigation
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_GESTURE_SWIPE_UP = 1374;
-
-    // OPEN: Settings > Storage > Dialog to format a storage volume
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_VOLUME_FORMAT = 1375;
-
-    // OPEN: DND onboarding activity
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_ZEN_ONBOARDING = 1380;
-
-    // OPEN: Settings > Display > Auto brightness
-    // CATEGORY: SETTINGS
-    // OS: P
-    SETTINGS_AUTO_BRIGHTNESS = 1381;
-
-     // OPEN: Settings > Connected Devices > Bluetooth
-    // CATEGORY: SETTINGS
-    // OS: P
-    BLUETOOTH_FRAGMENT = 1390;
-
-    // Screen: DND Settings > Notifications
-    // OS: P
-    SETTINGS_ZEN_NOTIFICATIONS = 1400;
-
-    // An event category for slices.
-    // OPEN: Slice became visible.
-    // CLOSE: Slice became invisible.
-    // ACTION: Slice was tapped.
-    SLICE = 1401;
-
-    // OPEN: Settings -> Developer Options -> Disable Bluetooth A2DP hardware
-    // offload
-    // CATEGORY: SETTINGS
-    // OS: P
-    DIALOG_BLUETOOTH_DISABLE_A2DP_HW_OFFLOAD = 1441;
-
-    // OPEN: Settings homepage
-    SETTINGS_HOMEPAGE = 1502;
-
-    // OPEN: Settings > Create shortcut(widget)
-    // CATEGORY: SETTINGS
-    // OS: Q
-    SETTINGS_CREATE_SHORTCUT = 1503;
-
-    // OPEN: Face Enroll introduction
-    // CATEGORY: SETTINGS
-    // OS: Q
-    FACE_ENROLL_INTRO = 1506;
-
-    // OPEN: Face Enroll introduction
-    // CATEGORY: SETTINGS
-    // OS: Q
-    FACE_ENROLL_ENROLLING = 1507;
-
-    // OPEN: Face Enroll introduction
-    // CATEGORY: SETTINGS
-    // OS: Q
-    FACE_ENROLL_FINISHED = 1508;
-
-    // OPEN: Face Enroll sidecar
-    // CATEGORY: SETTINGS
-    // OS: Q
-    FACE_ENROLL_SIDECAR = 1509;
-
-    // OPEN: Settings > Add face > Error dialog
-    // OS: Q
-    DIALOG_FACE_ERROR = 1510;
-
-    // OPEN: Settings > Security > Face
-    // CATEGORY: SETTINGS
-    // OS: Q
-    FACE = 1511;
-
-   // OPEN: Settings > Acessibility > HearingAid pairing instructions dialog
-    // CATEGORY: SETTINGS
-    // OS: Q
-    DIALOG_ACCESSIBILITY_HEARINGAID = 1512;
-
-    // OPEN: Settings > Add face
-    // OS: Q
-    FACE_ENROLL_PREVIEW = 1554;
-
-    // OPEN: Settings > Network & Internet > Wi-Fi > Add network
-    // CATEGORY: SETTINGS
-    // OS: Q
-    SETTINGS_WIFI_ADD_NETWORK = 1556;
-
-    // OPEN: Settings > System > Input & Gesture > Reach up gesture
-    // OS: Q
-    SETTINGS_GESTURE_WAKE_LOCK_SCREEN = 1557;
-
-    // OPEN: Settings > System > Input & Gesture > Wake screen
-    SETTINGS_GESTURE_WAKE_SCREEN = 1570;
-
-    // OPEN: Settings > Network & internet > Mobile network
-    MOBILE_NETWORK = 1571;
-
-    // OPEN: Settings > Network & internet > Mobile network > Choose network
-    MOBILE_NETWORK_SELECT = 1581;
-
-    // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog
-    MOBILE_DATA_DIALOG = 1582;
-
-    // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog
-    MOBILE_ROAMING_DIALOG = 1583;
-
-    // Settings > Display > Lock screen display > On lock screen
-    LOCK_SCREEN_NOTIFICATION_CONTENT = 1584;
-
-    // ConfirmDeviceCredentials > BiometricPrompt
-    BIOMETRIC_FRAGMENT = 1585;
-
-    // OPEN: Biometric Enrollment (android.settings.BIOMETRIC_ENROLL action intent)
-    BIOMETRIC_ENROLL_ACTIVITY = 1586;
-
-    // OPEN: Settings > Privacy
-    TOP_LEVEL_PRIVACY = 1587;
-
-    // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions >
-    // Allow apps to override
-    // CATEGORY: SETTINGS
-    // OS: Q
-    NOTIFICATION_ZEN_MODE_OVERRIDING_APPS = 1588;
-
-
-    // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions >
-    // Allow apps to override > Choose app
-    // CATEGORY: SETTINGS
-    // OS: Q
-    NOTIFICATION_ZEN_MODE_OVERRIDING_APP = 1589;
-
-    // OPEN: Settings > Developer options > Disable > Info dialog
-    DIALOG_DISABLE_DEVELOPMENT_OPTIONS = 1591;
-
-    // OPEN: WifiDppConfiguratorActivity (android.settings.WIFI_DPP_CONFIGURATOR_XXX action intents)
-    SETTINGS_WIFI_DPP_CONFIGURATOR = 1595;
-
-    // OPEN: WifiDppEnrolleeActivity (android.settings.WIFI_DPP_ENROLLEE_XXX action intents)
-    SETTINGS_WIFI_DPP_ENROLLEE = 1596;
-
-    // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access
-    SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597;
-
-
-
-    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
-    // > Do Not Disturb behavior
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_RULE_SETTINGS = 1604;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
-    // > Do Not Disturb behavior > Custom
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_RULE_SOUND_SETTINGS = 1605;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
-    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_RULE_DEFAULT_SETTINGS = 1606;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
-    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
-    // > Notification restriction
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_RULE_NOTIFICATION_RESTRICTIONS = 1608;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
-    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
-    // > Notification restriction > Custom
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_RULE_VIS_EFFECTS = 1609;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
-    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
-    // > Notification restriction > Custom > Allow messages
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_RULE_MESSAGES = 1610;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
-    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
-    // > Notification restriction > Custom > Allow calls
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_RULE_CALLS = 1611;
-
-    // OPEN: Settings > Sound > Do Not Disturb > Click footer link if custom settings applied
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
-
-    // OPEN: Settings > Developer Options > Graphics Driver Preferences
-    // CATEGORY: SETTINGS
-    // OS: Q
-    SETTINGS_GRAPHICS_DRIVER_DASHBOARD = 1613;
-
-    // OPEN: Settings > Accessibility > Vibration > Ring vibration
-    // CATEGORY: SETTINGS
-    // OS: Q
-    ACCESSIBILITY_VIBRATION_RING = 1620;
-
-    // OPEN: Settings > System > Input & Gesture > Skip songs
-    SETTINGS_GESTURE_SKIP = 1624;
-
-    // OPEN: Settings > System > Input & Gesture > Silence alerts
-    SETTINGS_GESTURE_SILENCE = 1625;
-
-    // OPEN: Settings > System > Input & Gesture > Tap to check
-    SETTINGS_GESTURE_TAP_SCREEN = 1626;
-
-    // OPEN: Settings > Network & internet > Click Mobile network to land on a page with a list of
-    // SIM/eSIM subscriptions.
-    MOBILE_NETWORK_LIST = 1627;
-
-    // OPEN: Settings > Display > Adaptive sleep
-    // OS: Q
-    SETTINGS_ADAPTIVE_SLEEP = 1628;
-
-    // OPEN: Settings > System > Aware
-    SETTINGS_AWARE = 1632;
-
-    // OPEN: Settings > System > Aware > Disable > Dialog
-    DIALOG_AWARE_DISABLE = 1633;
-
-    // OPEN: Settings > Settings > Network & internet > Click Mobile network to land on page with
-    // details for a SIM/eSIM mobile network > Click edit icon to bring up a rename dialog.
-    // OS: Q
-    MOBILE_NETWORK_RENAME_DIALOG = 1642;
-
-    // OPEN: Set new password (android.app.action.SET_NEW_PASSWORD action intent)
-    // CATEGORY: SETTINGS
-    // OS: Q
-    SET_NEW_PASSWORD_ACTIVITY = 1644;
-
-    // Panel for Internet Connectivity
-    PANEL_INTERNET_CONNECTIVITY = 1654;
-
-    // Panel for Volume
-    PANEL_VOLUME = 1655;
-
-    // Panel for NFC
-    PANEL_NFC = 1656;
-
-    // Panel for Media Output
-    PANEL_MEDIA_OUTPUT = 1657;
-
-    // Mapping: go/at-mapping
-    PAGE_ATSSI = 1667;
-
-    PAGE_ATSII = 1668;
-
-    PAGE_ATUS = 1669;
-
-    PAGE_ATSSP = 1670;
-
-    PAGE_ATSAP = 1671;
-
-    PAGE_ATSCP = 1672;
-
-    PAGE_ATHNP = 1673;
-
-    // OPEN: Accessibility detail settings (android.settings.ACCESSIBILITY_DETAILS_SETTINGS intent)
-    ACCESSIBILITY_DETAILS_SETTINGS = 1682;
-
-    // Open: Settings will show the conditional when Grayscale mode is on
-    SETTINGS_CONDITION_GRAYSCALE_MODE = 1683;
-
-    // Panel for Wifi
-    PANEL_WIFI = 1687;
-
-    // Open: Settings > Special App Access > Do not disturb control for app
-    ZEN_ACCESS_DETAIL = 1692;
-
-    // OPEN: Settings > Face > Remove face
-    // OS: Q
-    DIALOG_FACE_REMOVE = 1693;
-
-    // Settings > Display > Theme
-    DARK_UI_SETTINGS = 1698;
-
-    // Settings > global bubble settings
-    BUBBLE_SETTINGS = 1699;
-
-    // Settings > app > bubble settings
-    APP_BUBBLE_SETTINGS = 1700;
-
-    // OPEN: Settings > System > Aware > Info dialog
-    DIALOG_AWARE_STATUS = 1701;
-
-    // Open: Settings > app > bubble settings > confirmation dialog
-    DIALOG_APP_BUBBLE_SETTINGS = 1702;
-
-    // OPEN: Settings > Pick SIM dialog
-    DIALOG_SIM_LIST = 1707;
-
-    // OPEN: Settings > Pick SIM (that supports calling) dialog
-    DIALOG_CALL_SIM_LIST = 1708;
-
-    // OPEN: Settings > Pick preferred SIM dialog
-    DIALOG_PREFERRED_SIM_PICKER = 1709;
-
-    // OPEN: Settings > Network & internet > Mobile network > Delete sim
-    DIALOG_DELETE_SIM_CONFIRMATION = 1713;
-
-    // OPEN: Settings >  Network & internet > Mobile network > Delete sim > (answer yes to
-    //       confirmation)
-    DIALOG_DELETE_SIM_PROGRESS = 1714;
-
-    // Settings > Apps and notifications > Notifications > Gentle notifications
-    GENTLE_NOTIFICATIONS_SCREEN = 1715;
-
-    // OPEN: Settings > System > Gestures > Global Actions Panel
-    // CATEGORY: SETTINGS
-    // OS: Q
-    GLOBAL_ACTIONS_PANEL_SETTINGS = 1728;
-
-    // OPEN: Settings > Display > Dark Theme
-    // CATEGORY: SETTINGS
-    // OS: Q
-    // Note: Only shows up on first time toggle
-    DIALOG_DARK_UI_INFO = 1740;
-
-    // OPEN: Settings > About phone > Legal information > Google Play system update licenses
-    // CATEGORY: SETTINGS
-    // OS: Q
-    MODULE_LICENSES_DASHBOARD = 1746;
-
-    // OPEN: Settings > System > Gestures > System navigation > Info icon
-    // CATEGORY: SETTINGS
-    // OS: Q
-    // Note: Info icon is visible only when gesture navigation is not available and disabled
-    SETTINGS_GESTURE_NAV_NOT_AVAILABLE_DLG = 1747;
-
-    // OPEN: Settings > System > Gestures > System navigation > Gear icon
-    // CATEGORY: SETTINGS
-    // OS: Q
-    // Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
-    SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
-
-    // OPEN: Settings > System > Aware > Aware Display
-    // CATEGORY: SETTINGS
-    // OS: Q
-    SETTINGS_AWARE_DISPLAY = 1750;
-
-    // OPEN: Settings > System > Input & Gesture > tap gesture
-    // CATEGORY: SETTINGS
-    // OS: Q
-    SETTINGS_GESTURE_TAP = 1751;
-    // ---- End Q Constants, all Q constants go above this line ----
-    // OPEN: Settings > Network & Internet > Wi-Fi > Click new network
-    // CATEGORY: SETTINGS
-    // OS: R
-    SETTINGS_WIFI_CONFIGURE_NETWORK = 1800;
-
-    // OPEN: Settings > Accessibility > Magnification
-    // CATEGORY: SETTINGS
-    // OS: R
-    // Note: Shows up only when Magnify with shortcut is enabled
-    // and under accessibility button mode.
-    DIALOG_TOGGLE_SCREEN_MAGNIFICATION_ACCESSIBILITY_BUTTON = 1801;
-
-    // OPEN: Settings > Accessibility > Magnification
-    // CATEGORY: SETTINGS
-    // OS: R
-    // Note: Shows up only when Magnify with shortcut is enabled.
-    // and under gesture navigation mode.
-    DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION = 1802;
-
-    // OPEN: Settings > Security & screen lock -> Encryption & credentials > Install a certificate
-    // CATEGORY: SETTINGS
-    // OS: R
-    INSTALL_CERTIFICATE_FROM_STORAGE = 1803;
-
-    // OPEN: Settings > Apps and notifications > Special app access > notification access >
-    // an app
-    // CATEGORY: SETTINGS
-    // OS: R
-    NOTIFICATION_ACCESS_DETAIL = 1804;
-
-    // OPEN: Settings > Developer Options > Platform Compat
-    // CATEGORY: SETTINGS
-    // OS: R
-    SETTINGS_PLATFORM_COMPAT_DASHBOARD = 1805;
-
-    // OPEN: Settings > Location -> Work profile tab
-    // CATEGORY: SETTINGS
-    // OS: R
-    LOCATION_WORK = 1806;
-
-    // OPEN: Settings > Account -> Work profile tab
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACCOUNT_WORK = 1807;
-
-    // OPEN: Settings > Developer Options > Bug report handler
-    // CATEGORY: SETTINGS
-    // OS: R
-    SETTINGS_BUGREPORT_HANDLER = 1808;
-
-    // Panel for adding Wi-Fi networks
-    // CATEGORY: SETTINGS
-    // OS: R
-    PANEL_ADD_WIFI_NETWORKS = 1809;
-
-    // OPEN: Settings > Accessibility > Enable the feature or shortcut > Show tutorial dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    DIALOG_ACCESSIBILITY_TUTORIAL = 1810;
-
-    // OPEN: Settings > Accessibility > Edit shortcut dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    DIALOG_ACCESSIBILITY_SERVICE_EDIT_SHORTCUT = 1812;
-
-    // OPEN: Settings > Accessibility > Magnification > Edit shortcut dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    DIALOG_MAGNIFICATION_EDIT_SHORTCUT = 1813;
-
-    // OPEN: Settings > Accessibility > Color correction > Edit shortcut dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    DIALOG_DALTONIZER_EDIT_SHORTCUT = 1814;
-
-    // OPEN: Settings > Accessibility > Magnification > Settings
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACCESSIBILITY_MAGNIFICATION_SETTINGS = 1815;
-
-    // OPEN: Settings > Accessibility > Magnification > Settings > Magnification area dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    DIALOG_MAGNIFICATION_CAPABILITY = 1816;
-
-    // OPEN: Settings > Accessibility > Color inversion
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACCESSIBILITY_COLOR_INVERSION_SETTINGS = 1817;
-
-    // OPEN: Settings > Accessibility > Color inversion > Edit shortcut dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    DIALOG_COLOR_INVERSION_EDIT_SHORTCUT = 1818;
-
-    // OPEN: Settings > Accessibility > Captions preference > Captions appearance
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACCESSIBILITY_CAPTION_APPEARANCE = 1819;
-
-    // OPEN: Settings > Accessibility > Captions preference > More options
-    // CATEGORY: SETTINGS
-    // OS: R
-    ACCESSIBILITY_CAPTION_MORE_OPTIONS = 1820;
-
-    // OPEN: Settings > Battery > Battery share
-    // CATEGORY: SETTINGS
-    // OS: R
-    FUELGAUGE_BATTERY_SHARE = 1821;
-
-    // OPEN: Settings -> Apps & Notifications -> Special App Access
-    // CATEGORY: SETTINGS
-    // OS: R
-    MANAGE_EXTERNAL_STORAGE = 1822;
-
-    // Open: Settings > DND > People
-    // OS: R
-    DND_PEOPLE = 1823;
-
-    // OPEN: Settings > Apps and notifications > App info > one of any app > Open by default
-    //       > Open supported links
-    // CATEGORY: SETTINGS
-    // OS: R
-    OPEN_SUPPORTED_LINKS = 1824;
-
-    // OPEN: Settings > Display > Dark theme > Set start time dialog
-    DIALOG_DARK_THEME_SET_START_TIME = 1825;
-
-    // OPEN: Settings > Display > Dark theme > Set end time dialog
-    DIALOG_DARK_THEME_SET_END_TIME = 1826;
-
-    // OPEN: Settings -> Sound -> Vibrate for calls
-    // CATEGORY: SETTINGS
-    // OS: R
-    VIBRATE_FOR_CALLS = 1827;
-
-    // OPEN: Settings > Connected devices > Connection preferences > NFC
-    // CATEGORY: SETTINGS
-    // OS: R
-    CONNECTION_DEVICE_ADVANCED_NFC = 1828;
-
-    // OPEN: Settings -> Apps & Notifications -> Special App Access
-    INTERACT_ACROSS_PROFILES = 1829;
-
-    // OPEN: Settings > Notifications > (app or conversations) > conversation
-    NOTIFICATION_CONVERSATION_SETTINGS = 1830;
-
-    // OPEN: Settings > Developer Options > Wireless debugging
-    // CATEGORY: SETTINGS
-    // OS: R
-    SETTINGS_ADB_WIRELESS = 1831;
-
-    // OPEN: Settings > Developer Options > Wireless debugging
-    //   > Pair device with pairing code > Pairing code dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    ADB_WIRELESS_DEVICE_PAIRING_DIALOG = 1832;
-
-    // OPEN: Settings > Developer Options > Wireless debugging
-    //   > Pair device with QR code > Scan QR code > Pairing device dialog
-    // CATEGORY: SETTINGS
-    // OS: R
-    ADB_WIRELESS_DEVICE_QR_PAIRING_DIALOG = 1833;
-
-    // OPEN: Settings > apps & notifications > notifications > conversations
-    // CATEGORY: SETTINGS
-    // OS: R
-    NOTIFICATION_CONVERSATION_LIST_SETTINGS = 1834;
-
-    // Panel for Media Output Group operation
-    // CATEGORY: SETTINGS
-    // OS: R
-    PANEL_MEDIA_OUTPUT_GROUP = 1835;
-
-    // OPEN: Settings > Developer Options > Wireless debugging
-    //   > Click on paired device
-    // CATEGORY: SETTINGS
-    // OS: R
-    ADB_WIRELESS_DEVICE_DETAILS = 1836;
-
-    // Open: Settings > Sound > Do Not Disturb > People > Conversations
-    // OS: R
-    DND_CONVERSATIONS = 1837;
-
-    // Open: Settings > Sound > Do Not Disturb > People > Calls
-    // OS: R
-    DND_CALLS = 1838;
-
-    // Open: Settings > Sound > Do Not Disturb > People > Messages
-    // OS: R
-    DND_MESSAGES = 1839;
-
-    // Open: Settings > Sound > Do Not Disturb > Apps > <Choose App>
-    // OS: R
-    DND_APPS_BYPASSING = 1840;
-
-    // OPEN: Settings > System > Gestures > One-Handed
-    // CATEGORY: SETTINGS
-    // OS: R QPR
-    SETTINGS_ONE_HANDED = 1841;
-
-    // OPEN: Settings > Battery > Advanced battery option
-    // CATEGORY: SETTINGS
-    // OS: R
-    FUELGAUGE_ADVANCED_BATTERY_OPTION = 1842;
-
-    // OPEN: Settings > System > Gestures > Power menu
-    // CATEGORY: SETTINGS
-    // OS: R
-    POWER_MENU_SETTINGS = 1843;
-
-    // OPEN: Settings > System > Gestures > Power menu > Device controls
-    // CATEGORY: SETTINGS
-    // OS: R
-    DEVICE_CONTROLS_SETTINGS = 1844;
-
-    // OPEN: Settings > Sound > Media
-    // CATEGORY: SETTINGS
-    // OS: R
-    MEDIA_CONTROLS_SETTINGS = 1845;
-
-    // OPEN: Settings > System > Gestures > Swipe for notification
-    // CATEGORY: SETTINGS
-    // OS: R QPR
-    SETTINGS_SWIPE_BOTTOM_TO_NOTIFICATION = 1846;
-
-    // OPEN: Settings > System > Gestures > Emergency SOS Gesture
-    // CATEGORY: SETTINGS
-    // OS: S
-    EMERGENCY_SOS_GESTURE_SETTINGS = 1847;
-
-    // OPEN: Settings > System > Gestures > Double tap
-    // CATEGORY: SETTINGS
-    // OS: S
-    SETTINGS_COLUMBUS = 1848;
-
-    // OPEN: Settings > Accessibility > Magnification > Settings > Magnification area > Magnification switch shortcut dialog
-    // CATEGORY: SETTINGS
-    // OS: S
-    DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = 1849;
-
-    // OPEN: Settings > Network & internet > Adaptive connectivity
-    // CATEGORY: SETTINGS
-    // OS: R QPR
-    ADAPTIVE_CONNECTIVITY_CATEGORY = 1850;
-
-    // OS: R QPR2
-    BLUETOOTH_PAIRING_RECEIVER = 1851;
-
-    // OPEN: Settings > Display > Screen timeout
-    // CATEGORY: SETTINGS
-    // OS: S
-    SCREEN_TIMEOUT = 1852;
-
-    // OPEN: Settings > Accessibility > Reduce Bright Colors
-    // CATEGORY: SETTINGS
-    // OS: S
-    REDUCE_BRIGHT_COLORS_SETTINGS = 1853;
-
-    // OPEN: Settings > Location > Time Zone Detection
-    // CATEGORY: SETTINGS
-    // OS: S
-    LOCATION_TIME_ZONE_DETECTION = 1854;
-
-    // OPEN: Settings > Developer options > Media transcode settings
-    // CATEGORY: SETTINGS
-    // OS: S
-    TRANSCODE_SETTINGS = 1855;
-}
diff --git a/core/proto/android/app/tvsettings_enums.proto b/core/proto/android/app/tvsettings_enums.proto
deleted file mode 100644
index 77bf98f..0000000
--- a/core/proto/android/app/tvsettings_enums.proto
+++ /dev/null
@@ -1,1132 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.app.tvsettings;
-option java_multiple_files = true;
-option java_outer_classname = "TvSettingsEnums";
-
-/** The performed action types */
-enum Action {
-
-    /**
-     * Denotes an unknown action. It is a filler that should generally be
-     * avoided.
-     */
-    ACTION_UNKNOWN = 0;
-
-    /**
-     * Denotes that a TvSettings page is being focused. (Previewing a page in
-     * two panel settings should NOT be considered as focusing on the page.)
-     */
-    PAGE_FOCUSED = 1;
-
-    /**
-     * Denotes that an entry (typically a leaf node of settings tree) is
-     * selected by a user.
-     */
-    ENTRY_SELECTED = 2;
-
-    /** Denotes that a toggle is clicked by a user. */
-    TOGGLE_INTERACTED = 3;
-
-    /**
-     * Denotes that a TvSettings page is being focused in the forward direction
-     * into the settings tree.
-     */
-    PAGE_FOCUSED_FORWARD = 4;
-
-    /**
-     * Denotes that a TvSettings page is being focused in the backward direction
-     * up the settings tree.
-     */
-    PAGE_FOCUSED_BACKWARD = 5;
-
-    /** Denotes that a toggle is turned on by a user. */
-    TOGGLED_ON = 6;
-
-    /** Denotes that a toggle is turned off by a user. */
-    TOGGLED_OFF = 7;
-
-}
-
-/**
- * Ids for TvSettings focusable pages or actionable entries
- *
- * For details of the scheme, please refer to the "Definition of item_id" and
- * "Evolve of item_id" sections in go/atv-settings-ww-logging-design.
- */
-enum ItemId {
-
-    option allow_alias = true;
-
-    // Filler that should be avoided
-    UNKNOWN = 0x00000000;
-
-    // TvSettings
-    TV_SETTINGS_ROOT = 0x00000001;
-
-    // TvSettings unknown/default classic page
-    PAGE_CLASSIC_DEFAULT = 0x00000002;
-
-    // TvSettings unknown/default slice page
-    PAGE_SLICE_DEFAULT = 0x00000003;
-
-    // TvSettings unknown/default entry
-    ENTRY_DEFAULT = 0x00000004;
-
-    // TvSettings > Suggested settings entry
-    SUGGESTED_SETTINGS = 0x00000010;
-
-    // TvSettings > Quick Settings
-    QUICK_SETTINGS = 0x00000011;
-
-    // VERSION 1: Starting with Q
-    // These are ordered in depth-first search manner.
-
-    // TvSettings > Network & Internet
-    NETWORK = 0x11000000;
-
-    // TvSettings > Network & Internet > Wi-Fi (toggle)
-    NETWORK_WIFI_ON_OFF = 0x11100000;
-
-    // TvSettings > Network & Internet >
-    // [A connected network entry in available networks list]
-    NETWORK_AP_INFO = 0x11200000;
-
-    // TvSettings > Network & Internet >
-    // [A connected network entry in available networks list] > Proxy settings
-    NETWORK_AP_INFO_PROXY_SETTINGS = 0x11210000;
-
-    // TvSettings > Network & Internet >
-    // [A connected network entry in available networks list] > IP settings
-    NETWORK_AP_INFO_IP_SETTINGS = 0x11220000;
-
-    // TvSettings > Network & Internet >
-    // [A connected network entry in available networks list] > Forget network
-    NETWORK_AP_INFO_FORGET_NETWORK = 0x11230000;
-
-    // TvSettings > Network & Internet >
-    // [A not connected network entry in available networks list]
-    NETWORK_NOT_CONNECTED_AP = 0x11300000;
-
-    // TvSettings > Network & Internet > See all
-    NETWORK_SEE_ALL = 0x11400000;
-
-    // TvSettings > Network & Internet > See fewer
-    NETWORK_SEE_FEWER = 0x11500000;
-
-    // TvSettings > Network & Internet > Add new network
-    NETWORK_ADD_NEW_NETWORK = 0x11600000;
-
-    // TvSettings > Network & Internet > Scanning always available (toggle)
-    NETWORK_ALWAYS_SCANNING_NETWORKS = 0x11700000;
-
-    // TvSettings > Network & Internet > Proxy settings (in Ethernet category)
-    NETWORK_ETHERNET_PROXY_SETTINGS = 0x11800000;
-
-    // TvSettings > Network & Internet > IP settings (in Ethernet category)
-    NETWORK_ETHERNET_IP_SETTINGS = 0x11900000;
-
-    // TvSettings > Account & Sign In (Slice)
-    ACCOUNT_SLICE = 0x12000000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account]
-    ACCOUNT_SLICE_REG_ACCOUNT = 0x12100000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Services
-    ACCOUNT_SLICE_REG_ACCOUNT_SERVICES = 0x12110000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Payment & Purchases
-    ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT = 0x12120000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Payment & Purchases >
-    // Require authentication for purchases (reauth interval)
-    ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH = 0x12121000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Payment & Purchases >
-    // Require authentication for purchases (reauth interval) > Always
-    ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH_ALWAYS = 0x12121100;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Payment & Purchases >
-    // Require authentication for purchases (reauth interval) > Every 30 minutes
-    ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH_30MINS = 0x12121200;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Payment & Purchases >
-    // Require authentication for purchases (reauth interval) > Never
-    ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH_NEVER = 0x12121300;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Google Assistant
-    ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT = 0x12130000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Google Assistant > SafeSearch filter (toggle)
-    ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_SAFE_SEARCH = 0x12131000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Google Assistant > Block offensive words (toggle)
-    ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_BLOCK_OFFENSIVE = 0x12132000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Google Assistant > Searchable apps
-    ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_SEARCHABLE_APPS = 0x12133000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Google Assistant > Personal results (toggle)
-    ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_PERSONAL_RESULTS = 0x12134000;
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] >
-    // Apps only mode (toggle)
-    ACCOUNT_SLICE_REG_ACCOUNT_APPS_ONLY_MODE = 0x12140000;
-
-    // Reserving [0x12150000, 0x12190000] for possible future settings
-
-    // TvSettings > Account & Sign In (Slice) > [A regular account] > Remove
-    ACCOUNT_SLICE_REG_ACCOUNT_REMOVE = 0x121A0000;
-
-    // Reserving [0x12200000, 0x12900000] for possible future settings
-
-    // TvSettings > Account & Sign In (Slice) > Add account...
-    ACCOUNT_SLICE_ADD_ACCOUNT = 0x12A00000;
-
-    // TvSettings > Account & Sign In (Classic)
-    ACCOUNT_CLASSIC = 0x13000000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account]
-    ACCOUNT_CLASSIC_REG_ACCOUNT = 0x13100000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account] > Sync now
-    ACCOUNT_CLASSIC_REG_ACCOUNT_SYNC_NOW = 0x13110000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account] >
-    // Remove account
-    ACCOUNT_CLASSIC_REG_ACCOUNT_REMOVE_ACCOUNT = 0x13120000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account] >
-    // [Choose synced apps] Calendar (toggle)
-    ACCOUNT_CLASSIC_REG_ACCOUNT_SYNC_CALENDAR = 0x13130000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account] >
-    // [Choose synced apps] Contacts (toggle)
-    ACCOUNT_CLASSIC_REG_ACCOUNT_SYNC_CONTACTS = 0x13140000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account] >
-    // [Choose synced apps] Google Play Movies & TV (toggle)
-    ACCOUNT_CLASSIC_REG_ACCOUNT_SYNC_GPMT = 0x13150000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account] >
-    // [Choose synced apps] Google Play Music (toggle)
-    ACCOUNT_CLASSIC_REG_ACCOUNT_SYNC_GPM = 0x13160000;
-
-    // TvSettings > Account & Sign In (Classic) > [A regular account] >
-    // [Choose synced apps] People details (toggle)
-    ACCOUNT_CLASSIC_REG_ACCOUNT_SYNC_PEOPLE = 0x13170000;
-
-    // Reserving [0x13200000, 0x13900000] for possible future settings
-
-    // TvSettings > Account & Sign In (Classic) > Add account
-    ACCOUNT_CLASSIC_ADD_ACCOUNT = 0x13A00000;
-
-    // TvSettings > Privacy
-    PRIVACY = 0x14000000;
-
-    // TvSettings > Privacy > Location
-    PRIVACY_LOCATION = 0x14100000;
-
-    // TvSettings > Privacy > Location > Location status (radio button)
-    PRIVACY_LOCATION_STATUS = 0x14110000;
-
-    // TvSettings > Privacy > Location > Location status (radio button) >
-    // Use Wi-Fi to estimate location
-    PRIVACY_LOCATION_STATUS_USE_WIFI = 0x14111000;
-
-    // TvSettings > Privacy > Location > Location status (radio button) > Off
-    PRIVACY_LOCATION_STATUS_OFF = 0x14112000;
-
-    // TvSettings > Privacy > Location > Scanning always available (toggle)
-    PRIVACY_LOCATION_ALWAYS_SCANNING_NETWORKS = 0x14120000;
-
-    // TvSettings > Privacy > Location > [An app that had recent requests]
-    PRIVACY_LOCATION_REQUESTED_APP = 0x14130000;
-
-    // TvSettings > Privacy > Usage & Diagnostics
-    PRIVACY_DIAGNOSTICS = 0x14200000;
-
-    // TvSettings > Privacy > Usage & Diagnostics > On (Toggle)
-    PRIVACY_DIAGNOSTICS_ON_OFF = 0x14210000;
-
-    // TvSettings > Privacy > Ads
-    PRIVACY_ADS = 0x14300000;
-
-    // The following three IDs may not actually be logged as they are within a
-    // GMSCore Activity but we reserve IDs for them.
-    // TvSettings > Privacy > Ads > Reset advertising ID
-    PRIVACY_ADS_RESET_AD_ID = 0x14310000;
-
-    // TvSettings > Privacy > Ads > Opt out of Ads Personalization
-    PRIVACY_ADS_OPT_OUT_PERSONALIZATION = 0x14320000;
-
-    // TvSettings > Privacy > Ads > Ads by Google (WebView)
-    PRIVACY_ADS_ADS_BY_GOOGLE = 0x14330000;
-
-    // TvSettings > Display & Sound
-    DISPLAY_SOUND = 0x15000000;
-
-    // TvSettings > Display & Sound > Advanced display settings
-    DISPLAY_SOUND_ADVANCED_DISPLAY = 0x15100000;
-
-    // TvSettings > Display & Sound > Advanced display settings >
-    // Allow game mode (toggle)
-    DISPLAY_SOUND_ADVANCED_DISPLAY_GAME_MODE = 0x15110000;
-
-    // TvSettings > Display & Sound > System sounds (toggle)
-    DISPLAY_SOUND_SYSTEM_SOUNDS = 0x15200000;
-
-    // TvSettings > Display & Sound > Advanced sound settings
-    DISPLAY_SOUND_ADVANCED_SOUNDS = 0x15300000;
-
-    // TvSettings > Display & Sound > Advanced sound settings > Select formats
-    DISPLAY_SOUND_ADVANCED_SOUNDS_SELECT_FORMATS = 0x15310000;
-
-    // TvSettings > Display & Sound > Advanced sound settings > Select formats >
-    // Auto...
-    DISPLAY_SOUND_ADVANCED_SOUNDS_SELECT_FORMATS_AUTO = 0x15311000;
-
-    // TvSettings > Display & Sound > Advanced sound settings > Select formats >
-    // None...
-    DISPLAY_SOUND_ADVANCED_SOUNDS_SELECT_FORMATS_NONE = 0x15312000;
-
-    // TvSettings > Display & Sound > Advanced sound settings > Select formats >
-    // Manual...
-    DISPLAY_SOUND_ADVANCED_SOUNDS_SELECT_FORMATS_MANUAL = 0x15313000;
-
-    // TvSettings > Display & Sound > Advanced sound settings >
-    // Dolby AC-4 (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_DAC4 = 0x15320000;
-
-    // TvSettings > Display & Sound > Advanced sound settings >
-    // Dolby Atmos in Dolby Digital Plus (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_DADDP = 0x15330000;
-
-    // TvSettings > Display & Sound > Advanced sound settings >
-    // Dolby Digital (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_DD = 0x15340000;
-
-    // TvSettings > Display & Sound > Advanced sound settings >
-    // Dolby Digital Plus (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_DDP = 0x15350000;
-
-    // TvSettings > Display & Sound > Advanced sound settings > DTS (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_DTS = 0x15360000;
-
-    // TvSettings > Display & Sound > Advanced sound settings > DTS-HD (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_DTSHD = 0x15370000;
-
-    // TvSettings > Display & Sound > Advanced sound settings > AAC (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_AAC = 0x15380000;
-
-    // TvSettings > Display & Sound > Advanced sound settings >
-    // Dolby TrueHD (toggle)
-    DISPLAY_SOUND_ADVANCED_SOUNDS_DTHD = 0x15390000;
-
-    // TvSettings > Apps
-    APPS = 0x16000000;
-
-    // TvSettings > Apps > See all apps
-    APPS_ALL_APPS = 0x16100000;
-
-    // TvSettings > Apps > See all apps > [An app entry]
-    APPS_ALL_APPS_APP_ENTRY = 0x16110000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Open
-    APPS_ALL_APPS_APP_ENTRY_OPEN = 0x16111000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Force stop
-    APPS_ALL_APPS_APP_ENTRY_FORCE_STOP = 0x16112000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Uninstall
-    APPS_ALL_APPS_APP_ENTRY_UNINSTALL = 0x16113000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Uninstall updates
-    APPS_ALL_APPS_APP_ENTRY_UNINSTALL_UPDATES = 0x16114000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Disable
-    APPS_ALL_APPS_APP_ENTRY_DISABLE = 0x16115000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Clear data
-    APPS_ALL_APPS_APP_ENTRY_CLEAR_DATA = 0x16116000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Clear cache
-    APPS_ALL_APPS_APP_ENTRY_CLEAR_CACHE = 0x16117000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Clear defaults
-    APPS_ALL_APPS_APP_ENTRY_CLEAR_DEFAULTS = 0x16118000;
-
-    // TvSettings > Apps > See all apps > [An app entry] >
-    // Notifications (toggle)
-    APPS_ALL_APPS_APP_ENTRY_NOTIFICATIONS = 0x16119000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Permissions
-    APPS_ALL_APPS_APP_ENTRY_PERMISSIONS = 0x1611A000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Enable
-    APPS_ALL_APPS_APP_ENTRY_ENABLE = 0x1611B000;
-
-    // TvSettings > Apps > See all apps > [An app entry] > Open source licenses
-    APPS_ALL_APPS_APP_ENTRY_LICENSES = 0x1611C000;
-
-    // TvSettings > Apps > See all apps > Show system apps
-    APPS_ALL_APPS_SHOW_SYSTEM_APPS = 0x16120000;
-
-    // TvSettings > Apps > App permissions
-    APPS_APP_PERMISSIONS = 0x16200000;
-
-    // TvSettings > Apps > App permission > Body sensors
-    APPS_APP_PERMISSIONS_BODY_SENSORS = 0x16210000;
-
-    // TvSettings > Apps > App permission > Calendar
-    APPS_APP_PERMISSIONS_CALENDAR = 0x16220000;
-
-    // TvSettings > Apps > App permission > Call logs
-    APPS_APP_PERMISSIONS_CALL_LOGS = 0x16230000;
-
-    // TvSettings > Apps > App permission > Camera
-    APPS_APP_PERMISSIONS_CAMERA = 0x16240000;
-
-    // TvSettings > Apps > App permission > Contacts
-    APPS_APP_PERMISSIONS_CONTACTS = 0x16250000;
-
-    // TvSettings > Apps > App permission > Location
-    APPS_APP_PERMISSIONS_LOCATION = 0x16260000;
-
-    // TvSettings > Apps > App permission > Microphone
-    APPS_APP_PERMISSIONS_MICROPHONE = 0x16270000;
-
-    // TvSettings > Apps > App permission > Phone
-    APPS_APP_PERMISSIONS_PHONE = 0x16280000;
-
-    // TvSettings > Apps > App permission > Physical activity
-    APPS_APP_PERMISSIONS_PHYSICAL_ACTIVITY = 0x16290000;
-
-    // TvSettings > Apps > App permission > SMS
-    APPS_APP_PERMISSIONS_SMS = 0x162A0000;
-
-    // TvSettings > Apps > App permission > Storage
-    APPS_APP_PERMISSIONS_STORAGE = 0x162B0000;
-
-    // TvSettings > Apps > App permission > Additional permissions
-    APPS_APP_PERMISSIONS_ADDITIONAL = 0x162C0000;
-
-    // TvSettings > Apps > App permission > Additional permissions >
-    // real all TV listings
-    APPS_APP_PERMISSIONS_ADDITIONAL_READ_TV_LISTINGS = 0x162C1000;
-
-    // TvSettings > Apps > App permission > Additional permissions >
-    // real instant messages
-    APPS_APP_PERMISSIONS_ADDITIONAL_READ_INSTANT_MESSAGES = 0x162C2000;
-
-    // TvSettings > Apps > App permission > Additional permissions >
-    // write instant messages
-    APPS_APP_PERMISSIONS_ADDITIONAL_WRITE_INSTANT_MESSAGES = 0x162C3000;
-
-    // TvSettings > Apps > Special app access
-    APPS_SPECIAL_APP_ACCESS = 0x16300000;
-
-    // TvSettings > Apps > Special app access > Energy optimization
-    APPS_SPECIAL_APP_ACCESS_ENERGY_OPTIMIZATION = 0x16310000;
-
-    // TvSettings > Apps > Special app access > Usage access
-    APPS_SPECIAL_APP_ACCESS_USAGE_ACCESS = 0x16320000;
-
-    // TvSettings > Apps > Special app access > Notification access
-    APPS_SPECIAL_APP_ACCESS_NOTIFICATION_ACCESS = 0x16330000;
-
-    // TvSettings > Apps > Special app access > Display over other apps
-    APPS_SPECIAL_APP_ACCESS_DISPLAY_OVER_OTHERS = 0x16340000;
-
-    // TvSettings > Apps > Special app access > Modify system settings
-    APPS_SPECIAL_APP_ACCESS_MODIFY_SYSTEM_SETTINGS = 0x16350000;
-
-    // TvSettings > Apps > Special app access > Picture-in-picture
-    APPS_SPECIAL_APP_ACCESS_PICTURE_IN_PICTURE = 0x16360000;
-
-    // TvSettings > Apps > Security & restrictions
-    APPS_SECURITY_RESTRICTIONS = 0x16400000;
-
-    // TvSettings > Apps > Security & restrictions > Unknown sources
-    APPS_SECURITY_RESTRICTIONS_UNKNOWN_SOURCES = 0x16410000;
-
-    // TvSettings > Apps > Security & restrictions > Verify apps (toggle)
-    APPS_SECURITY_RESTRICTIONS_VERIFY_APPS = 0x16420000;
-
-    // TvSettings > Apps > Security & restrictions > Create restricted profile
-    APPS_SECURITY_RESTRICTIONS_CREATE_PROFILE = 0x16430000;
-
-    // TvSettings > Apps > Security & restrictions > Enter restricted profile
-    APPS_SECURITY_RESTRICTIONS_ENTER_PROFILE = 0x16440000;
-
-    // TvSettings > Apps > Security & restrictions >
-    // Allowed apps (Restricted Profile)
-    APPS_SECURITY_RESTRICTIONS_PROFILE_ALLOWED_APPS = 0x16450000;
-
-    // TvSettings > Apps > Security & restrictions >
-    // Change pin (Restricted Profile)
-    APPS_SECURITY_RESTRICTIONS_PROFILE_CHANGE_PIN = 0x16460000;
-
-    // TvSettings > Apps > Security & restrictions >
-    // Delete restricted profile
-    APPS_SECURITY_RESTRICTIONS_DELETE_PROFILE = 0x16470000;
-
-    // TvSettings > Apps > Security & restrictions >
-    // Exit restricted profile
-    APPS_SECURITY_RESTRICTIONS_EXIT_PROFILE = 0x16480000;
-
-    // TvSettings > System (same as TvSettings > Device Preferences)
-    SYSTEM = 0x17000000;
-
-    // TvSettings > System > About
-    SYSTEM_ABOUT = 0x17100000;
-
-    // TvSettings > System > System update
-    SYSTEM_ABOUT_SYSTEM_UPDATE = 0x17110000;
-
-    // TvSettings > System > Device name
-    SYSTEM_ABOUT_DEVICE_NAME = 0x17120000;
-
-    // TvSettings > System > Factory reset
-    SYSTEM_ABOUT_FACTORY_RESET = 0x17130000;
-
-    // TvSettings > System > Status
-    SYSTEM_ABOUT_STATUS = 0x17140000;
-
-    // TvSettings > System > Legal information
-    SYSTEM_ABOUT_LEGAL_INFO = 0x17150000;
-
-    // TvSettings > System > Legal information > Open source licenses
-    SYSTEM_ABOUT_LEGAL_INFO_OPEN_SOURCE = 0x17151000;
-
-    // TvSettings > System > Legal information > Google legal
-    SYSTEM_ABOUT_LEGAL_INFO_GOOGLE_LEGAL = 0x17152000;
-
-    // TvSettings > System > Legal information > System WebView licenses
-    SYSTEM_ABOUT_LEGAL_INFO_SYSTEM_WEBVIEW = 0x17153000;
-
-    // TvSettings > System > Build
-    SYSTEM_ABOUT_BUILD = 0x17160000;
-
-    // TvSettings > System > Date & time
-    SYSTEM_DATE_TIME = 0x17200000;
-
-    // TvSettings > System > Date & time > Automatic data & time
-    SYSTEM_DATE_TIME_AUTOMATIC = 0x17210000;
-
-    // TvSettings > System > Date & time > Automatic data & time >
-    // Use network-provided time
-    SYSTEM_DATE_TIME_AUTOMATIC_USE_NETWORK_TIME = 0x17211000;
-
-    // TvSettings > System > Date & time > Automatic data & time > Off
-    SYSTEM_DATE_TIME_AUTOMATIC_OFF = 0x17212000;
-
-    // TvSettings > System > Date & time > Set date
-    SYSTEM_DATE_TIME_SET_DATE = 0x17220000;
-
-    // TvSettings > System > Date & time > Set time
-    SYSTEM_DATE_TIME_SET_TIME = 0x17230000;
-
-    // TvSettings > System > Date & time > Set time zone
-    SYSTEM_DATE_TIME_SET_TIME_ZONE = 0x17240000;
-
-    // TvSettings > System > Date & time > Set time zone > [A time zone button]
-    SYSTEM_DATE_TIME_SET_TIME_ZONE_BUTTON = 0x17241000;
-
-    // TvSettings > System > Date & time > Use 24-hour format (toggle)
-    SYSTEM_DATE_TIME_USE_24_HOUR_FORMAT = 0x17250000;
-
-    // TvSettings > System > Language
-    SYSTEM_LANGUAGE = 0x17300000;
-
-    // TvSettings > System > Language > [A language button]
-    SYSTEM_LANGUAGE_BUTTON = 0x17310000;
-
-    // TvSettings > System > Keyboard
-    SYSTEM_KEYBOARD = 0x17400000;
-
-    // TvSettings > System > Keyboard > Current keyboard
-    SYSTEM_KEYBOARD_CURRENT_KEYBOARD = 0x17410000;
-
-    // TvSettings > System > Keyboard > Gboard Settings
-    SYSTEM_KEYBOARD_GBOARD_SETTINGS = 0x17420000;
-
-    // TvSettings > System > Keyboard > Gboard Settings > Languages
-    SYSTEM_KEYBOARD_GBOARD_SETTINGS_LANGUAGES = 0x17421000;
-
-    // TvSettings > System > Keyboard > Gboard Settings > Terms of services
-    SYSTEM_KEYBOARD_GBOARD_SETTINGS_TOS = 0x17422000;
-
-    // TvSettings > System > Keyboard > Gboard Settings > Privacy policy
-    SYSTEM_KEYBOARD_GBOARD_SETTINGS_PRIVACY_POLICY = 0x17423000;
-
-    // TvSettings > System > Keyboard > Gboard Settings > Open source licenses
-    SYSTEM_KEYBOARD_GBOARD_SETTINGS_OPEN_SOURCE = 0x17424000;
-
-    // TvSettings > System > Keyboard > Gboard Settings >
-    // Share usage statistics (toggle)
-    SYSTEM_KEYBOARD_GBOARD_SETTINGS_SHARE_USAGE_STATS = 0x17425000;
-
-    // TvSettings > System > Keyboard > Manage keyboards
-    SYSTEM_KEYBOARD_MANAGE_KEYBOARDS = 0x17430000;
-
-    // TvSettings > System > Storage
-    SYSTEM_STORAGE = 0x17500000;
-
-    // TvSettings > System > Internal shared storage
-    SYSTEM_STORAGE_INTERNAL_STORAGE = 0x17510000;
-
-    // TvSettings > System > Internal shared storage > Apps
-    SYSTEM_STORAGE_INTERNAL_STORAGE_APPS = 0x17511000;
-
-    // TvSettings > System > Internal shared storage >
-    // Cached data (brings up "Clear cached data?" dialog upon click)
-    SYSTEM_STORAGE_INTERNAL_STORAGE_CACHED = 0x17512000;
-
-    // TvSettings > System > Ambient mode
-    SYSTEM_AMBIENT = 0x17600000;
-
-    // TvSettings > System > Ambient mode > Start now
-    SYSTEM_AMBIENT_START = 0x17610000;
-
-    // TvSettings > System > Ambient mode > Settings
-    SYSTEM_AMBIENT_SETTINGS = 0x17620000;
-
-    // TvSettings > System > Ambient mode > Settings > Google Photos (Channels)
-    SYSTEM_AMBIENT_SETTINGS_CHANNEL_GP = 0x17621000;
-
-    // TvSettings > System > Ambient mode > Settings > Art gallery (Channels)
-    SYSTEM_AMBIENT_SETTINGS_CHANNEL_AG = 0x17622000;
-
-    // TvSettings > System > Ambient mode > Settings >
-    // Cinematic videos (Channels)
-    SYSTEM_AMBIENT_SETTINGS_CHANNEL_CV = 0x17623000;
-
-    // TvSettings > System > Ambient mode > Settings > Experimental (Channels)
-    SYSTEM_AMBIENT_SETTINGS_CHANNEL_EXP = 0x17624000;
-
-    // TvSettings > System > Ambient mode > Settings > Weather
-    SYSTEM_AMBIENT_SETTINGS_WEATHER = 0x17625000;
-
-    // TvSettings > System > Ambient mode > Settings > Weather > Hide
-    SYSTEM_AMBIENT_SETTINGS_WEATHER_HIDE = 0x17625100;
-
-    // TvSettings > System > Ambient mode > Settings > Weather > Celsius (Unit)
-    SYSTEM_AMBIENT_SETTINGS_WEATHER_UNIT_C = 0x17625200;
-
-    // TvSettings > System > Ambient mode > Settings > Weather >
-    // Fahrenheit (Unit)
-    SYSTEM_AMBIENT_SETTINGS_WEATHER_UNIT_F = 0x17625300;
-
-    // TvSettings > System > Ambient mode > Settings > Weather > Both (Unit)
-    SYSTEM_AMBIENT_SETTINGS_WEATHER_UNIT_BOTH = 0x17625400;
-
-    // TvSettings > System > Ambient mode > Settings > Time
-    SYSTEM_AMBIENT_SETTINGS_TIME = 0x17626000;
-
-    // TvSettings > System > Ambient mode > Settings > Time > Hide
-    SYSTEM_AMBIENT_SETTINGS_TIME_HIDE = 0x17626100;
-
-    // TvSettings > System > Ambient mode > Settings > Time > Show
-    SYSTEM_AMBIENT_SETTINGS_TIME_SHOW = 0x17626200;
-
-    // TvSettings > System > Ambient mode > Settings > Device information
-    SYSTEM_AMBIENT_SETTINGS_DEVICE_INFO = 0x17627000;
-
-    // TvSettings > System > Ambient mode > Settings > Device information > Hide
-    SYSTEM_AMBIENT_SETTINGS_DEVICE_INFO_HIDE = 0x17627100;
-
-    // TvSettings > System > Ambient mode > Settings > Device information > Show
-    SYSTEM_AMBIENT_SETTINGS_DEVICE_INFO_SHOW = 0x17627200;
-
-    // TvSettings > System > Ambient mode > Settings > Personal photo data
-    SYSTEM_AMBIENT_SETTINGS_PPD = 0x17628000;
-
-    // TvSettings > System > Ambient mode > Settings > Personal photo data >
-    // Hide
-    SYSTEM_AMBIENT_SETTINGS_PPD_HIDE = 0x17628100;
-
-    // TvSettings > System > Ambient mode > Settings > Personal photo data >
-    // Show
-    SYSTEM_AMBIENT_SETTINGS_PPD_SHOW = 0x17628200;
-
-    // TvSettings > System > Ambient mode > Settings > Portrait Google Photos
-    SYSTEM_AMBIENT_SETTINGS_PGP = 0x17629000;
-
-    // TvSettings > System > Ambient mode > Settings > Portrait Google Photos >
-    // Hide
-    SYSTEM_AMBIENT_SETTINGS_PGP_HIDE = 0x17629100;
-
-    // TvSettings > System > Ambient mode > Settings > Portrait Google Photos >
-    // Show
-    SYSTEM_AMBIENT_SETTINGS_PGP_SHOW = 0x17629200;
-
-    // TvSettings > System > Ambient mode > Settings > Portrait Google Photos >
-    // Show pairs
-    SYSTEM_AMBIENT_SETTINGS_PGP_SHOW_PAIRS = 0x17629300;
-
-    // TvSettings > System > Ambient mode > Settings > Personal photo curation
-    SYSTEM_AMBIENT_SETTINGS_PPC = 0x1762A000;
-
-    // TvSettings > System > Ambient mode > Settings > Personal photo curation >
-    // All albums
-    SYSTEM_AMBIENT_SETTINGS_PPC_ALL_ALBUMS = 0x1762A100;
-
-    // TvSettings > System > Ambient mode > Settings > Personal photo curation >
-    // Live albums only
-    SYSTEM_AMBIENT_SETTINGS_PPC_LIVE_ALBUMS = 0x1762A200;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED = 0x1762B000;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed > 5s
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_5S = 0x1762B100;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed > 10s
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_10S = 0x1762B200;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed > 30s
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_30S = 0x1762B300;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed > 1m
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_1M = 0x1762B400;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed > 3m
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_3M = 0x1762B500;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed > 5m
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_5M = 0x1762B600;
-
-    // TvSettings > System > Ambient mode > Settings > Slideshow speed > 10m
-    SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_10M = 0x1762B700;
-
-    // TvSettings > System > Energy saver
-    SYSTEM_ENERGYSAVER = 0x17700000;
-
-    // TvSettings > System > Energy saver > Turn off display after
-    SYSTEM_ENERGYSAVER_START_DELAY = 0x17710000;
-
-    // TvSettings > System > Energy saver > Turn off display after > 15 minutes
-    SYSTEM_ENERGYSAVER_START_DELAY_15M = 0x17711000;
-
-    // TvSettings > System > Energy saver > Turn off display after > 30 minutes
-    SYSTEM_ENERGYSAVER_START_DELAY_30M = 0x17712000;
-
-    // TvSettings > System > Energy saver > Turn off display after > 1 hour
-    SYSTEM_ENERGYSAVER_START_DELAY_1H = 0x17713000;
-
-    // TvSettings > System > Energy saver > Turn off display after > 3 hours
-    SYSTEM_ENERGYSAVER_START_DELAY_3H = 0x17714000;
-
-    // TvSettings > System > Energy saver > Turn off display after > 6 hours
-    SYSTEM_ENERGYSAVER_START_DELAY_6H = 0x17715000;
-
-    // TvSettings > System > Energy saver > Turn off display after > 12 hours
-    SYSTEM_ENERGYSAVER_START_DELAY_12H = 0x17716000;
-
-    // TvSettings > System > Energy saver > Turn off display after > Never
-    SYSTEM_ENERGYSAVER_START_DELAY_NEVER = 0x17717000;
-
-    // TvSettings > System > Accessibility
-    SYSTEM_A11Y = 0x17800000;
-
-    // TvSettings > System > Accessibility > Captions
-    SYSTEM_A11Y_CAPTIONS = 0x17810000;
-
-    // TvSettings > System > Accessibility > Captions > Display (toggle)
-    SYSTEM_A11Y_CAPTIONS_DISPLAY_ON_OFF = 0x17811000;
-
-    // TvSettings > System > Accessibility > Captions > Language
-    SYSTEM_A11Y_CAPTIONS_LANGUAGE = 0x17812000;
-
-    // TvSettings > System > Accessibility > Captions > Language > [A language]
-    SYSTEM_A11Y_CAPTIONS_LANGUAGE_BUTTON = 0x17812100;
-
-    // TvSettings > System > Accessibility > Captions > Text size
-    SYSTEM_A11Y_CAPTIONS_TEXT_SIZE = 0x17813000;
-
-    // TvSettings > System > Accessibility > Captions > Text size > Very small
-    SYSTEM_A11Y_CAPTIONS_TEXT_SIZE_VERY_SMALL = 0x17813100;
-
-    // TvSettings > System > Accessibility > Captions > Text size > Small
-    SYSTEM_A11Y_CAPTIONS_TEXT_SIZE_SMALL = 0x17813200;
-
-    // TvSettings > System > Accessibility > Captions > Text size > Normal
-    SYSTEM_A11Y_CAPTIONS_TEXT_SIZE_NORMAL = 0x17813300;
-
-    // TvSettings > System > Accessibility > Captions > Text size > Large
-    SYSTEM_A11Y_CAPTIONS_TEXT_SIZE_LARGE = 0x17813400;
-
-    // TvSettings > System > Accessibility > Captions > Text size > Very large
-    SYSTEM_A11Y_CAPTIONS_TEXT_SIZE_VERY_LARGE = 0x17813500;
-
-    // TvSettings > System > Accessibility > Captions >
-    // White on black (radio button)
-    SYSTEM_A11Y_CAPTIONS_WHITE_ON_BLACK = 0x17814000;
-
-    // TvSettings > System > Accessibility > Captions >
-    // Black on white (radio button)
-    SYSTEM_A11Y_CAPTIONS_BLACK_ON_WHITE = 0x17815000;
-
-    // TvSettings > System > Accessibility > Captions >
-    // Yellow on black (radio button)
-    SYSTEM_A11Y_CAPTIONS_YELLOW_ON_BLACK = 0x17816000;
-
-    // TvSettings > System > Accessibility > Captions >
-    // Yellow on blue (radio button)
-    SYSTEM_A11Y_CAPTIONS_YELLOW_ON_BLUE = 0x17817000;
-
-    // TvSettings > System > Accessibility > Captions > Custom
-    SYSTEM_A11Y_CAPTIONS_CUSTOM = 0x17818000;
-
-    // TvSettings > System > Accessibility > Captions > Custom > Font family
-    SYSTEM_A11Y_CAPTIONS_CUSTOM_FONT = 0x17818100;
-
-    // TvSettings > System > Accessibility > Captions > Custom > Text color
-    SYSTEM_A11Y_CAPTIONS_CUSTOM_TEXT_COLOR = 0x17818200;
-
-    // TvSettings > System > Accessibility > Captions > Custom > Text opacity
-    SYSTEM_A11Y_CAPTIONS_CUSTOM_TEXT_OPACITY = 0x17818300;
-
-    // TvSettings > System > Accessibility > Captions > Custom > Edge type
-    SYSTEM_A11Y_CAPTIONS_CUSTOM_EDGE_TYPE = 0x17818400;
-
-    // TvSettings > System > Accessibility > Captions > Custom > Edge color
-    SYSTEM_A11Y_CAPTIONS_CUSTOM_EDGE_COLOR = 0x17818500;
-
-    // TvSettings > System > Accessibility > Captions > Custom >
-    // Show background (toggle)
-    SYSTEM_A11Y_CAPTIONS_SHOW_BACKGROUND = 0x17818600;
-
-    // TvSettings > System > Accessibility > Captions > Custom >
-    // Background color
-    SYSTEM_A11Y_CAPTIONS_BACKGROUND_COLOR = 0x17818700;
-
-    // TvSettings > System > Accessibility > Captions > Custom >
-    // Background opacity
-    SYSTEM_A11Y_CAPTIONS_BACKGROUND_OPACITY = 0x17818800;
-
-    // TvSettings > System > Accessibility > Captions > Custom >
-    // Show window (toggle)
-    SYSTEM_A11Y_CAPTIONS_SHOW_WINDOW = 0x17818900;
-
-    // TvSettings > System > Accessibility > Captions > Custom > Window color
-    SYSTEM_A11Y_CAPTIONS_WINDOW_COLOR = 0x17818A00;
-
-    // TvSettings > System > Accessibility > Captions > Custom > Window opacity
-    SYSTEM_A11Y_CAPTIONS_WINDOW_OPACITY = 0x17818B00;
-
-    // TvSettings > System > Accessibility > High contrast text (toggle)
-    SYSTEM_A11Y_HIGH_CONTRAST_TEXT = 0x17820000;
-
-    // TvSettings > System > Accessibility > Text to speech
-    SYSTEM_A11Y_TTS = 0x17830000;
-
-    // TvSettings > System > Accessibility > Text to speech > [Select an engine]
-    SYSTEM_A11Y_TTS_ENGINE_SELECT = 0x17831000;
-
-    // TvSettings > System > Accessibility > Text to speech >
-    // Engine configuration
-    SYSTEM_A11Y_TTS_ENGINE_CONFIG = 0x17832000;
-
-    // TvSettings > System > Accessibility > Text to speech >
-    // Engine configuration > Language
-    SYSTEM_A11Y_TTS_ENGINE_CONFIG_LANGUAGE = 0x17832100;
-
-    // TvSettings > System > Accessibility > Text to speech >
-    // Engine configuration > Language > Button
-    SYSTEM_A11Y_TTS_ENGINE_CONFIG_LANGUAGE_CHOOSE_LANGUAGE = 0x17832110;
-
-    // TvSettings > System > Accessibility > Text to speech >
-    // Engine configuration > Settings for Google Text-to-speech Engine
-    SYSTEM_A11Y_TTS_ENGINE_CONFIG_SETTINGS_GTTS_ENGINE = 0x17832200;
-
-    // TvSettings > System > Accessibility > Text to speech >
-    // Engine configuration > Install voice data
-    SYSTEM_A11Y_TTS_ENGINE_CONFIG_INSTALL_VOICE_DATA = 0x17832300;
-
-    // TvSettings > System > Accessibility > Text to speech > Speech rate
-    SYSTEM_A11Y_TTS_SPEECH_RATE = 0x17833000;
-
-    // TvSettings > System > Accessibility > Text to speech >
-    // Listen to an example
-    SYSTEM_A11Y_TTS_LISTEN_EXAMPLE = 0x17834000;
-
-    // TvSettings > System > Accessibility > Accessibility shortcut
-    SYSTEM_A11Y_SHORTCUT = 0x17840000;
-
-    // TvSettings > System > Accessibility > Accessibility shortcut >
-    // Enable (toggle)
-    SYSTEM_A11Y_SHORTCUT_ON_OFF = 0x17841000;
-
-    // TvSettings > System > Accessibility > Accessibility shortcut >
-    // Shortcut services
-    SYSTEM_A11Y_SHORTCUT_SERVICE = 0x17842000;
-
-    // TvSettings > System > Accessibility > TalkBack
-    SYSTEM_A11Y_TALKBACK = 0x17850000;
-
-    // TvSettings > System > Accessibility > TalkBack > Enable (toggle)
-    SYSTEM_A11Y_TALKBACK_ON_OFF = 0x17851000;
-
-    // TvSettings > System > Accessibility > TalkBack > Configuration
-    SYSTEM_A11Y_TALKBACK_CONFIG = 0x17852000;
-
-    // TvSettings > System > Accessibility > Accessibility Menu
-    SYSTEM_A11Y_A11Y_MENU = 0x17860000;
-
-    // TvSettings > System > Accessibility > Accessibility Menu >
-    // Enable (toggle)
-    SYSTEM_A11Y_A11Y_MENU_ON_OFF = 0x17861000;
-
-    // TvSettings > System > Accessibility > Accessibility Menu > Configuration
-    SYSTEM_A11Y_A11Y_MENU_CONFIG = 0x17862000;
-
-    // TvSettings > System > Accessibility > Select to Speak
-    SYSTEM_A11Y_STS = 0x17870000;
-
-    // TvSettings > System > Accessibility > Select to Speak > Enable (toggle)
-    SYSTEM_A11Y_STS_ON_OFF = 0x17871000;
-
-    // TvSettings > System > Accessibility > Select to Speak > Configuration
-    SYSTEM_A11Y_STS_CONFIG = 0x17872000;
-
-    // TvSettings > System > Accessibility > Switch Access
-    SYSTEM_A11Y_SWITCH_ACCESS = 0x17880000;
-
-    // TvSettings > System > Accessibility > Switch Access > Enable (Toggle)
-    SYSTEM_A11Y_SWITCH_ACCESS_ON_OFF = 0x17881000;
-
-    // TvSettings > System > Accessibility > Switch Access > Configuration
-    SYSTEM_A11Y_SWITCH_ACCESS_CONFIG = 0x17882000;
-
-    // TvSettings > System > Reboot
-    SYSTEM_REBOOT = 0x17900000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings)
-    PREFERENCES_HOME_SCREEN = 0x17A00000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS = 0x17A10000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels > Play Next
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS_PN = 0x17A11000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels > Play Next > On (toggle)
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS_PN_ON_OFF = 0x17A11100;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels > Play Next > Google Play Movies & TV (toggle)
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS_PN_GPMT = 0x17A11200;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels > Play Next > Google Play Music (toggle)
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS_PN_GPM = 0x17A11300;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels > Play Next > Promotional channels (toggle)
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS_PN_PROMOTIONAL = 0x17A11400;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels > Home screen channels
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS_HOME_SCREEN = 0x17A12000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Customize channels > Promotional channels
-    PREFERENCES_HOME_SCREEN_CUSTOMIZE_CHANNELS_PROMOTIONAL = 0x17A13000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Enable video previews (toggle)
-    PREFERENCES_HOME_SCREEN_VIDEO_PREVIEWS = 0x17A20000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Enable audio previews (toggle)
-    PREFERENCES_HOME_SCREEN_AUDIO_PREVIEWS = 0x17A30000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Reorder apps
-    PREFERENCES_HOME_SCREEN_REORDER_APPS = 0x17A40000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Reorder games
-    PREFERENCES_HOME_SCREEN_REORDER_GAMES = 0x17A50000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Android TV Home open source licenses
-    PREFERENCES_HOME_SCREEN_ATVH_OPEN_SOURCE = 0x17A60000;
-
-    // TvSettings > Device Preferences > Home screen (in classic TvSettings) >
-    // Android TV Core Services open source licenses
-    PREFERENCES_HOME_SCREEN_ATVCS_OPEN_SOURCE = 0x17A70000;
-
-    // TvSettings > Device Preferences > Google Assistant
-    PREFERENCES_ASSISTANT = 0x17B00000;
-
-    // TvSettings > Device Preferences > Google Assistant > Accounts
-    PREFERENCES_ASSISTANT_ACCOUNTS = 0x17B10000;
-
-    // TvSettings > Device Preferences > Google Assistant > Accept permissions
-    PREFERENCES_ASSISTANT_ACCEPT_PERMISSIONS = 0x17B20000;
-
-    // TvSettings > Device Preferences > Google Assistant > View permissions
-    PREFERENCES_ASSISTANT_VIEW_PERMISSIONS = 0x17B30000;
-
-    // TvSettings > Device Preferences > Google Assistant > Searchable apps
-    // (aliasing ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_SEARCHABLE_APPS)
-    PREFERENCES_ASSISTANT_SEARCHABLE_APPS = 0x12133000;
-
-    // TvSettings > Device Preferences > Google Assistant > SafeSearch filter
-    // (aliasing ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_SAFE_SEARCH)
-    PREFERENCES_ASSISTANT_SAFESEARCH_FILTER = 0x12131000;
-
-    // TvSettings > Device Preferences > Google Assistant >
-    // Block offensive words
-    // (aliasing ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_BLOCK_OFFENSIVE)
-    PREFERENCES_ASSISTANT_BLOCK_OFFENSIVE = 0x12132000;
-
-    // TvSettings > Device Preferences > Google Assistant > Open source licenses
-    PREFERENCES_ASSISTANT_OPEN_SOURCE = 0x17B40000;
-
-    // TvSettings > Device Preferences > Chromecast Android Shell
-    PREFERENCES_CHROMECAST_SHELL = 0x17C00000;
-
-    // TvSettings > Device Preferences > Chromecast Android Shell >
-    // Open source licenses
-    PREFERENCES_CHROMECAST_SHELL_OPEN_SOURCE = 0x17C10000;
-
-    // TvSettings > Device Preferences > Screen saver
-    PREFERENCES_SCREENSAVER = 0x17D00000;
-
-    // TvSettings > Device Preferences > Screen saver > Screen saver (chooser)
-    PREFERENCES_SCREENSAVER_CHOOSER = 0x17D10000;
-
-    // TvSettings > Device Preferences > Screen saver > Screen saver (chooser) >
-    // Turn screen off
-    PREFERENCES_SCREENSAVER_CHOOSER_SCREEN_OFF = 0x17D11000;
-
-    // TvSettings > Device Preferences > Screen saver > Screen saver (chooser) >
-    // Backdrop
-    PREFERENCES_SCREENSAVER_CHOOSER_BACKDROP = 0x17D12000;
-
-    // TvSettings > Device Preferences > Screen saver > Screen saver (chooser) >
-    // Colors
-    PREFERENCES_SCREENSAVER_CHOOSER_COLORS = 0x17D13000;
-
-    // TvSettings > Device Preferences > Screen saver > When to start
-    PREFERENCES_SCREENSAVER_START_DELAY = 0x17D20000;
-
-    // TvSettings > Device Preferences > Screen saver > When to start >
-    // 5 minutes
-    PREFERENCES_SCREENSAVER_START_DELAY_5M = 0x17D21000;
-
-    // TvSettings > Device Preferences > Screen saver > When to start >
-    // 15 minutes
-    PREFERENCES_SCREENSAVER_START_DELAY_15M = 0x17D22000;
-
-    // TvSettings > Device Preferences > Screen saver > When to start >
-    // 30 minutes
-    PREFERENCES_SCREENSAVER_START_DELAY_30M = 0x17D23000;
-
-    // TvSettings > Device Preferences > Screen saver > When to start >
-    // 1 hour
-    PREFERENCES_SCREENSAVER_START_DELAY_1H = 0x17D24000;
-
-    // TvSettings > Device Preferences > Screen saver > When to start >
-    // 2 hours
-    PREFERENCES_SCREENSAVER_START_DELAY_2H = 0x17D25000;
-
-    // TvSettings > Device Preferences > Screen saver > Start now
-    PREFERENCES_SCREENSAVER_START_NOW = 0x17D30000;
-
-    // TvSettings > Connected Devices (Slice)
-    CONNECTED_SLICE = 0x18000000;
-
-    // TvSettings > Connected Devices (Slice) > Connect remote or headphones
-    CONNECTED_SLICE_CONNECT_NEW_DEVICES = 0x18100000;
-
-    // TvSettings > Connected Devices (Slice) > [A connected device]
-    CONNECTED_SLICE_DEVICE_ENTRY = 0x18200000;
-
-    // TvSettings > Connected Devices (Slice) > [A connected device] >
-    // Remote update
-    CONNECTED_SLICE_DEVICE_ENTRY_UPDATE = 0x18210000;
-
-    // TvSettings > Connected Devices (Slice) > [A connected device] > Rename
-    CONNECTED_SLICE_DEVICE_ENTRY_RENAME = 0x18220000;
-
-    // TvSettings > Connected Devices (Slice) > [A connected device] > Forget
-    CONNECTED_SLICE_DEVICE_ENTRY_FORGET = 0x18230000;
-
-    // TvSettings > Connected Devices (Slice) > HDMI-CEC
-    CONNECTED_SLICE_HDMICEC = 0x18300000;
-
-    // TvSettings > Connected Devices (Slice) > HDMI-CEC > Enable (toggle)
-    CONNECTED_SLICE_HDMICEC_ON_OFF = 0x18310000;
-
-    // TvSettings > Connected Devices (aliasing CONNECTED_SLICE)
-    CONNECTED_CLASSIC = 0x18000000;
-
-    // TvSettings > Connected Devices > Connect remote
-    // (aliasing CONNECTED_SLICE_CONNECT_NEW_DEVICES)
-    CONNECTED_CLASSIC_CONNECT_REMOTE = 0x18100000;
-
-    // TvSettings > Connected Devices > [A connected device]
-    // (aliasing CONNECTED_SLICE_DEVICE_ENTRY)
-    CONNECTED_CLASSIC_DEVICE_ENTRY = 0x18200000;
-
-    // TvSettings > Connected Devices > [A connected device] > Update
-    // (aliasing CONNECTED_SLICE_DEVICE_ENTRY_UPDATE)
-    CONNECTED_CLASSIC_DEVICE_ENTRY_UPDATE = 0x18210000;
-
-    // TvSettings > Connected Devices > [A connected device] > Rename
-    // (aliasing CONNECTED_SLICE_DEVICE_ENTRY_RENAME)
-    CONNECTED_CLASSIC_DEVICE_ENTRY_RENAME = 0x18220000;
-
-    // TvSettings > Connected Devices > [A connected device] > Forget
-    // (aliasing CONNECTED_SLICE_DEVICE_ENTRY_FORGET)
-    CONNECTED_CLASSIC_DEVICE_ENTRY_FORGET = 0x18230000;
-
-    // TvSettings > Connected Devices > HDMI-CEC
-    // (aliasing CONNECTED_SLICE_HDMICEC)
-    CONNECTED_CLASSIC_HDMICEC = 0x18300000;
-
-    // TvSettings > Connected Devices > HDMI-CEC > Enable (toggle)
-    // (aliasing CONNECTED_SLICE_HDMICEC_ON_OFF)
-    CONNECTED_CLASSIC_HDMICEC_ON_OFF = 0x18310000;
-
-    // TvSettings > Help & Feedback
-    FEEDBACK = 0x19000000;
-
-    // TvSettings > Help & Feedback > Send feedback
-    FEEDBACK_SEND = 0x19100000;
-}
diff --git a/core/proto/android/bluetooth/a2dp/enums.proto b/core/proto/android/bluetooth/a2dp/enums.proto
deleted file mode 100644
index 5a025bd..0000000
--- a/core/proto/android/bluetooth/a2dp/enums.proto
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.bluetooth.a2dp;
-
-option java_outer_classname = "BluetoothA2dpProtoEnums";
-option java_multiple_files = true;
-
-// A2dp playback state enum, defined from:
-// frameworks/base/core/java/android/bluetooth/BluetoothA2dp.java
-enum PlaybackStateEnum {
-    PLAYBACK_STATE_UNKNOWN = 0;
-    PLAYBACK_STATE_PLAYING = 10;
-    PLAYBACK_STATE_NOT_PLAYING = 11;
-}
-
-enum AudioCodingModeEnum {
-    AUDIO_CODING_MODE_UNKNOWN = 0;
-    AUDIO_CODING_MODE_HARDWARE = 1;
-    AUDIO_CODING_MODE_SOFTWARE = 2;
-}
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
deleted file mode 100644
index dc60ede..0000000
--- a/core/proto/android/bluetooth/enums.proto
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.bluetooth;
-
-option java_outer_classname = "BluetoothProtoEnums";
-option java_multiple_files = true;
-
-// Bluetooth connection states.
-enum ConnectionStateEnum {
-    CONNECTION_STATE_DISCONNECTED = 0;
-    CONNECTION_STATE_CONNECTING = 1;
-    CONNECTION_STATE_CONNECTED = 2;
-    CONNECTION_STATE_DISCONNECTING = 3;
-}
-
-// Bluetooth Adapter Enable and Disable Reasons
-enum EnableDisableReasonEnum {
-    ENABLE_DISABLE_REASON_UNSPECIFIED = 0;
-    ENABLE_DISABLE_REASON_APPLICATION_REQUEST = 1;
-    ENABLE_DISABLE_REASON_AIRPLANE_MODE = 2;
-    ENABLE_DISABLE_REASON_DISALLOWED = 3;
-    ENABLE_DISABLE_REASON_RESTARTED = 4;
-    ENABLE_DISABLE_REASON_START_ERROR = 5;
-    ENABLE_DISABLE_REASON_SYSTEM_BOOT = 6;
-    ENABLE_DISABLE_REASON_CRASH = 7;
-    ENABLE_DISABLE_REASON_USER_SWITCH = 8;
-    ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
-    ENABLE_DISABLE_REASON_FACTORY_RESET = 10;
-    ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED = 11;
-}
-
-enum DirectionEnum {
-    DIRECTION_UNKNOWN = 0;
-    DIRECTION_OUTGOING = 1;
-    DIRECTION_INCOMING = 2;
-}
-
-// First item is the default value, other values follow Bluetooth spec definition
-enum LinkTypeEnum {
-    // Link type is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
-    LINK_TYPE_UNKNOWN = 0xFFF;
-    LINK_TYPE_SCO = 0x00;
-    LINK_TYPE_ACL = 0x01;
-    LINK_TYPE_ESCO = 0x02;
-}
-
-enum DeviceInfoSrcEnum {
-    DEVICE_INFO_SRC_UNKNOWN = 0;
-    // Within Android Bluetooth stack
-    DEVICE_INFO_INTERNAL = 1;
-    // Outside Android Bluetooth stack
-    DEVICE_INFO_EXTERNAL = 2;
-}
-
-enum DeviceTypeEnum {
-    DEVICE_TYPE_UNKNOWN = 0;
-    DEVICE_TYPE_CLASSIC = 1;
-    DEVICE_TYPE_LE = 2;
-    DEVICE_TYPE_DUAL = 3;
-}
-
-// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
-enum TransportTypeEnum {
-    TRANSPORT_TYPE_AUTO = 0;
-    TRANSPORT_TYPE_BREDR = 1;
-    TRANSPORT_TYPE_LE = 2;
-}
-
-// Bond state enum
-// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
-enum BondStateEnum {
-    BOND_STATE_UNKNOWN = 0;
-    BOND_STATE_NONE = 10;
-    BOND_STATE_BONDING = 11;
-    BOND_STATE_BONDED = 12;
-}
-
-// Sub states within the bonding general state
-enum BondSubStateEnum {
-    BOND_SUB_STATE_UNKNOWN = 0;
-    BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED = 1;
-    BOND_SUB_STATE_LOCAL_PIN_REQUESTED = 2;
-    BOND_SUB_STATE_LOCAL_PIN_REPLIED = 3;
-    BOND_SUB_STATE_LOCAL_SSP_REQUESTED = 4;
-    BOND_SUB_STATE_LOCAL_SSP_REPLIED = 5;
-}
-
-enum UnbondReasonEnum {
-    UNBOND_REASON_UNKNOWN = 0;
-    UNBOND_REASON_AUTH_FAILED = 1;
-    UNBOND_REASON_AUTH_REJECTED = 2;
-    UNBOND_REASON_AUTH_CANCELED = 3;
-    UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
-    UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
-    UNBOND_REASON_AUTH_TIMEOUT = 6;
-    UNBOND_REASON_REPEATED_ATTEMPTS = 7;
-    UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
-    UNBOND_REASON_REMOVED = 9;
-}
-
-enum SocketTypeEnum {
-    SOCKET_TYPE_UNKNOWN = 0;
-    SOCKET_TYPE_RFCOMM = 1;
-    SOCKET_TYPE_SCO = 2;
-    SOCKET_TYPE_L2CAP_BREDR = 3;
-    SOCKET_TYPE_L2CAP_LE = 4;
-}
-
-enum SocketConnectionstateEnum {
-    SOCKET_CONNECTION_STATE_UNKNOWN = 0;
-    // Socket acts as a server waiting for connection
-    SOCKET_CONNECTION_STATE_LISTENING = 1;
-    // Socket acts as a client trying to connect
-    SOCKET_CONNECTION_STATE_CONNECTING = 2;
-    // Socket is connected
-    SOCKET_CONNECTION_STATE_CONNECTED = 3;
-    // Socket tries to disconnect from remote
-    SOCKET_CONNECTION_STATE_DISCONNECTING = 4;
-    // This socket is closed
-    SOCKET_CONNECTION_STATE_DISCONNECTED = 5;
-}
-
-enum SocketRoleEnum {
-    SOCKET_ROLE_UNKNOWN = 0;
-    SOCKET_ROLE_LISTEN = 1;
-    SOCKET_ROLE_CONNECTION = 2;
-}
diff --git a/core/proto/android/bluetooth/hci/enums.proto b/core/proto/android/bluetooth/hci/enums.proto
deleted file mode 100644
index ef894e5..0000000
--- a/core/proto/android/bluetooth/hci/enums.proto
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.bluetooth.hci;
-
-option java_outer_classname = "BluetoothHciProtoEnums";
-option java_multiple_files = true;
-
-// HCI command opcodes (OCF+OGF) from Bluetooth 5.0 specification Vol 2, Part E, Section 7
-// Original definition: system/bt/stack/include/hcidefs.h
-enum CommandEnum {
-    // Opcode is at most 2 bytes (0xFFFF), thus 0xFFFFF must not be a valid value
-    CMD_UNKNOWN = 0xFFFFF;
-    // Link control commands 0x0400
-    CMD_INQUIRY = 0x0401;
-    CMD_INQUIRY_CANCEL = 0x0402;
-    CMD_PERIODIC_INQUIRY_MODE = 0x0403;
-    CMD_EXIT_PERIODIC_INQUIRY_MODE = 0x0404;
-    CMD_CREATE_CONNECTION = 0x0405;
-    CMD_DISCONNECT = 0x0406;
-    CMD_ADD_SCO_CONNECTION = 0x0407; // Deprecated since Bluetooth 1.2
-    CMD_CREATE_CONNECTION_CANCEL = 0x0408;
-    CMD_ACCEPT_CONNECTION_REQUEST = 0x0409;
-    CMD_REJECT_CONNECTION_REQUEST = 0x040A;
-    CMD_LINK_KEY_REQUEST_REPLY = 0x040B;
-    CMD_LINK_KEY_REQUEST_NEG_REPLY = 0x040C;
-    CMD_PIN_CODE_REQUEST_REPLY = 0x040D;
-    CMD_PIN_CODE_REQUEST_NEG_REPLY = 0x040E;
-    CMD_CHANGE_CONN_PACKET_TYPE = 0x040F;
-    CMD_AUTHENTICATION_REQUESTED = 0x0411;
-    CMD_SET_CONN_ENCRYPTION = 0x0413;
-    CMD_CHANGE_CONN_LINK_KEY = 0x0415;
-    CMD_MASTER_LINK_KEY = 0x0417;
-    CMD_RMT_NAME_REQUEST = 0x0419;
-    CMD_RMT_NAME_REQUEST_CANCEL = 0x041A;
-    CMD_READ_RMT_FEATURES = 0x041B;
-    CMD_READ_RMT_EXT_FEATURES = 0x041C;
-    CMD_READ_RMT_VERSION_INFO = 0x041D;
-    CMD_READ_RMT_CLOCK_OFFSET = 0x041F;
-    CMD_READ_LMP_HANDLE = 0x0420;
-    CMD_SETUP_ESCO_CONNECTION = 0x0428;
-    CMD_ACCEPT_ESCO_CONNECTION = 0x0429;
-    CMD_REJECT_ESCO_CONNECTION = 0x042A;
-    CMD_IO_CAPABILITY_REQUEST_REPLY = 0x042B;
-    CMD_USER_CONF_REQUEST_REPLY = 0x042C;
-    CMD_USER_CONF_VALUE_NEG_REPLY = 0x042D;
-    CMD_USER_PASSKEY_REQ_REPLY = 0x042E;
-    CMD_USER_PASSKEY_REQ_NEG_REPLY = 0x042F;
-    CMD_REM_OOB_DATA_REQ_REPLY = 0x0430;
-    CMD_REM_OOB_DATA_REQ_NEG_REPLY = 0x0433;
-    CMD_IO_CAP_REQ_NEG_REPLY = 0x0434;
-    // BEGIN: AMP commands (not used in system/bt)
-    CMD_CREATE_PHYSICAL_LINK = 0x0435;
-    CMD_ACCEPT_PHYSICAL_LINK = 0x0436;
-    CMD_DISCONNECT_PHYSICAL_LINK = 0x0437;
-    CMD_CREATE_LOGICAL_LINK = 0x0438;
-    CMD_ACCEPT_LOGICAL_LINK = 0x0439;
-    CMD_DISCONNECT_LOGICAL_LINK = 0x043A;
-    CMD_LOGICAL_LINK_CANCEL = 0x043B;
-    CMD_FLOW_SPEC_MODIFY = 0x043C;
-    // END: AMP commands
-    CMD_ENH_SETUP_ESCO_CONNECTION = 0x043D;
-    CMD_ENH_ACCEPT_ESCO_CONNECTION = 0x043E;
-    CMD_TRUNCATED_PAGE = 0x043F;
-    CMD_TRUNCATED_PAGE_CANCEL = 0x0440;
-    CMD_SET_CLB = 0x0441;
-    CMD_RECEIVE_CLB = 0x0442;
-    CMD_START_SYNC_TRAIN = 0x0443;
-    CMD_RECEIVE_SYNC_TRAIN = 0x0444;
-    CMD_REM_OOB_EXTENDED_DATA_REQ_REPLY = 0x0445; // Not currently used in system/bt
-    // Link policy commands 0x0800
-    CMD_HOLD_MODE = 0x0801;
-    CMD_SNIFF_MODE = 0x0803;
-    CMD_EXIT_SNIFF_MODE = 0x0804;
-    CMD_PARK_MODE = 0x0805;
-    CMD_EXIT_PARK_MODE = 0x0806;
-    CMD_QOS_SETUP = 0x0807;
-    CMD_ROLE_DISCOVERY = 0x0809;
-    CMD_SWITCH_ROLE = 0x080B;
-    CMD_READ_POLICY_SETTINGS = 0x080C;
-    CMD_WRITE_POLICY_SETTINGS = 0x080D;
-    CMD_READ_DEF_POLICY_SETTINGS = 0x080E;
-    CMD_WRITE_DEF_POLICY_SETTINGS = 0x080F;
-    CMD_FLOW_SPECIFICATION = 0x0810;
-    CMD_SNIFF_SUB_RATE = 0x0811;
-    // Host controller baseband commands 0x0C00
-    CMD_SET_EVENT_MASK = 0x0C01;
-    CMD_RESET = 0x0C03;
-    CMD_SET_EVENT_FILTER = 0x0C05;
-    CMD_FLUSH = 0x0C08;
-    CMD_READ_PIN_TYPE = 0x0C09;
-    CMD_WRITE_PIN_TYPE = 0x0C0A;
-    CMD_CREATE_NEW_UNIT_KEY = 0x0C0B;
-    CMD_GET_MWS_TRANS_LAYER_CFG = 0x0C0C; // Deprecated (not used in spec)
-    CMD_READ_STORED_LINK_KEY = 0x0C0D;
-    CMD_WRITE_STORED_LINK_KEY = 0x0C11;
-    CMD_DELETE_STORED_LINK_KEY = 0x0C12;
-    CMD_CHANGE_LOCAL_NAME = 0x0C13;
-    CMD_READ_LOCAL_NAME = 0x0C14;
-    CMD_READ_CONN_ACCEPT_TOUT = 0x0C15;
-    CMD_WRITE_CONN_ACCEPT_TOUT = 0x0C16;
-    CMD_READ_PAGE_TOUT = 0x0C17;
-    CMD_WRITE_PAGE_TOUT = 0x0C18;
-    CMD_READ_SCAN_ENABLE = 0x0C19;
-    CMD_WRITE_SCAN_ENABLE = 0x0C1A;
-    CMD_READ_PAGESCAN_CFG = 0x0C1B;
-    CMD_WRITE_PAGESCAN_CFG = 0x0C1C;
-    CMD_READ_INQUIRYSCAN_CFG = 0x0C1D;
-    CMD_WRITE_INQUIRYSCAN_CFG = 0x0C1E;
-    CMD_READ_AUTHENTICATION_ENABLE = 0x0C1F;
-    CMD_WRITE_AUTHENTICATION_ENABLE = 0x0C20;
-    CMD_READ_ENCRYPTION_MODE = 0x0C21; // Deprecated
-    CMD_WRITE_ENCRYPTION_MODE = 0x0C22; // Deprecated
-    CMD_READ_CLASS_OF_DEVICE = 0x0C23;
-    CMD_WRITE_CLASS_OF_DEVICE = 0x0C24;
-    CMD_READ_VOICE_SETTINGS = 0x0C25;
-    CMD_WRITE_VOICE_SETTINGS = 0x0C26;
-    CMD_READ_AUTOMATIC_FLUSH_TIMEOUT = 0x0C27;
-    CMD_WRITE_AUTOMATIC_FLUSH_TIMEOUT = 0x0C28;
-    CMD_READ_NUM_BCAST_REXMITS = 0x0C29;
-    CMD_WRITE_NUM_BCAST_REXMITS = 0x0C2A;
-    CMD_READ_HOLD_MODE_ACTIVITY = 0x0C2B;
-    CMD_WRITE_HOLD_MODE_ACTIVITY = 0x0C2C;
-    CMD_READ_TRANSMIT_POWER_LEVEL = 0x0C2D;
-    CMD_READ_SCO_FLOW_CTRL_ENABLE = 0x0C2E;
-    CMD_WRITE_SCO_FLOW_CTRL_ENABLE = 0x0C2F;
-    CMD_SET_HC_TO_HOST_FLOW_CTRL = 0x0C31;
-    CMD_HOST_BUFFER_SIZE = 0x0C33;
-    CMD_HOST_NUM_PACKETS_DONE = 0x0C35;
-    CMD_READ_LINK_SUPER_TOUT = 0x0C36;
-    CMD_WRITE_LINK_SUPER_TOUT = 0x0C37;
-    CMD_READ_NUM_SUPPORTED_IAC = 0x0C38;
-    CMD_READ_CURRENT_IAC_LAP = 0x0C39;
-    CMD_WRITE_CURRENT_IAC_LAP = 0x0C3A;
-    CMD_READ_PAGESCAN_PERIOD_MODE = 0x0C3B; // Deprecated
-    CMD_WRITE_PAGESCAN_PERIOD_MODE = 0x0C3C; // Deprecated
-    CMD_READ_PAGESCAN_MODE = 0x0C3D; // Deprecated
-    CMD_WRITE_PAGESCAN_MODE = 0x0C3E; // Deprecated
-    CMD_SET_AFH_CHANNELS = 0x0C3F;
-    CMD_READ_INQSCAN_TYPE = 0x0C42;
-    CMD_WRITE_INQSCAN_TYPE = 0x0C43;
-    CMD_READ_INQUIRY_MODE = 0x0C44;
-    CMD_WRITE_INQUIRY_MODE = 0x0C45;
-    CMD_READ_PAGESCAN_TYPE = 0x0C46;
-    CMD_WRITE_PAGESCAN_TYPE = 0x0C47;
-    CMD_READ_AFH_ASSESSMENT_MODE = 0x0C48;
-    CMD_WRITE_AFH_ASSESSMENT_MODE = 0x0C49;
-    CMD_READ_EXT_INQ_RESPONSE = 0x0C51;
-    CMD_WRITE_EXT_INQ_RESPONSE = 0x0C52;
-    CMD_REFRESH_ENCRYPTION_KEY = 0x0C53;
-    CMD_READ_SIMPLE_PAIRING_MODE = 0x0C55;
-    CMD_WRITE_SIMPLE_PAIRING_MODE = 0x0C56;
-    CMD_READ_LOCAL_OOB_DATA = 0x0C57;
-    CMD_READ_INQ_TX_POWER_LEVEL = 0x0C58;
-    CMD_WRITE_INQ_TX_POWER_LEVEL = 0x0C59;
-    CMD_READ_ERRONEOUS_DATA_RPT = 0x0C5A;
-    CMD_WRITE_ERRONEOUS_DATA_RPT = 0x0C5B;
-    CMD_ENHANCED_FLUSH = 0x0C5F;
-    CMD_SEND_KEYPRESS_NOTIF = 0x0C60;
-    CMD_READ_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C61;
-    CMD_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C62;
-    CMD_SET_EVENT_MASK_PAGE_2 = 0x0C63;
-    CMD_READ_LOCATION_DATA = 0x0C64;
-    CMD_WRITE_LOCATION_DATA = 0x0C65;
-    CMD_READ_FLOW_CONTROL_MODE = 0x0C66;
-    CMD_WRITE_FLOW_CONTROL_MODE = 0x0C67;
-    CMD_READ_ENHANCED_TX_PWR_LEVEL = 0x0C68; // Not currently used in system/bt
-    CMD_READ_BE_FLUSH_TOUT = 0x0C69;
-    CMD_WRITE_BE_FLUSH_TOUT = 0x0C6A;
-    CMD_SHORT_RANGE_MODE = 0x0C6B;
-    CMD_READ_BLE_HOST_SUPPORT = 0x0C6C;
-    CMD_WRITE_BLE_HOST_SUPPORT = 0x0C6D;
-    CMD_SET_MWS_CHANNEL_PARAMETERS = 0x0C6E;
-    CMD_SET_EXTERNAL_FRAME_CONFIGURATION = 0x0C6F;
-    CMD_SET_MWS_SIGNALING = 0x0C70;
-    CMD_SET_MWS_TRANSPORT_LAYER = 0x0C71;
-    CMD_SET_MWS_SCAN_FREQUENCY_TABLE = 0x0C72;
-    CMD_SET_MWS_PATTERN_CONFIGURATION = 0x0C73;
-    CMD_SET_RESERVED_LT_ADDR = 0x0C74;
-    CMD_DELETE_RESERVED_LT_ADDR = 0x0C75;
-    CMD_WRITE_CLB_DATA = 0x0C76;
-    CMD_READ_SYNC_TRAIN_PARAM = 0x0C77;
-    CMD_WRITE_SYNC_TRAIN_PARAM = 0x0C78;
-    CMD_READ_SECURE_CONNS_SUPPORT = 0x0C79;
-    CMD_WRITE_SECURE_CONNS_SUPPORT = 0x0C7A;
-    CMD_READ_AUTHED_PAYLOAD_TIMEOUT = 0x0C7B; // Not currently used in system/bt
-    CMD_WRITE_AUTHED_PAYLOAD_TIMEOUT = 0x0C7C; // Not currently used in system/bt
-    CMD_READ_LOCAL_OOB_EXTENDED_DATA = 0x0C7D; // Not currently used in system/bt
-    CMD_READ_EXTENDED_PAGE_TIMEOUT = 0x0C7E; // Not currently used in system/bt
-    CMD_WRITE_EXTENDED_PAGE_TIMEOUT = 0x0C7F; // Not currently used in system/bt
-    CMD_READ_EXTENDED_INQUIRY_LENGTH = 0x0C80; // Not currently used in system/bt
-    CMD_WRITE_EXTENDED_INQUIRY_LENGTH = 0x0C81; // Not currently used in system/bt
-    // Informational parameter commands 0x1000
-    CMD_READ_LOCAL_VERSION_INFO = 0x1001;
-    CMD_READ_LOCAL_SUPPORTED_CMDS = 0x1002;
-    CMD_READ_LOCAL_FEATURES = 0x1003;
-    CMD_READ_LOCAL_EXT_FEATURES = 0x1004;
-    CMD_READ_BUFFER_SIZE = 0x1005;
-    CMD_READ_COUNTRY_CODE = 0x1007; // Deprecated
-    CMD_READ_BD_ADDR = 0x1009;
-    CMD_READ_DATA_BLOCK_SIZE = 0x100A;
-    CMD_READ_LOCAL_SUPPORTED_CODECS = 0x100B;
-    // Status parameter commands 0x1400
-    CMD_READ_FAILED_CONTACT_COUNTER = 0x1401;
-    CMD_RESET_FAILED_CONTACT_COUNTER = 0x1402;
-    CMD_GET_LINK_QUALITY = 0x1403;
-    CMD_READ_RSSI = 0x1405;
-    CMD_READ_AFH_CH_MAP = 0x1406;
-    CMD_READ_CLOCK = 0x1407;
-    CMD_READ_ENCR_KEY_SIZE = 0x1408;
-    CMD_READ_LOCAL_AMP_INFO = 0x1409;
-    CMD_READ_LOCAL_AMP_ASSOC = 0x140A;
-    CMD_WRITE_REMOTE_AMP_ASSOC = 0x140B;
-    CMD_GET_MWS_TRANSPORT_CFG = 0x140C; // Not currently used in system/bt
-    CMD_SET_TRIGGERED_CLK_CAPTURE = 0x140D; // Not currently used in system/bt
-    // Testing commands 0x1800
-    CMD_READ_LOOPBACK_MODE = 0x1801;
-    CMD_WRITE_LOOPBACK_MODE = 0x1802;
-    CMD_ENABLE_DEV_UNDER_TEST_MODE = 0x1803;
-    CMD_WRITE_SIMP_PAIR_DEBUG_MODE = 0x1804;
-    CMD_ENABLE_AMP_RCVR_REPORTS = 0x1807;
-    CMD_AMP_TEST_END = 0x1808;
-    CMD_AMP_TEST = 0x1809;
-    CMD_WRITE_SECURE_CONN_TEST_MODE = 0x180A; // Not currently used in system/bt
-    // BLE commands 0x2000
-    CMD_BLE_SET_EVENT_MASK = 0x2001;
-    CMD_BLE_READ_BUFFER_SIZE = 0x2002;
-    CMD_BLE_READ_LOCAL_SPT_FEAT = 0x2003;
-    CMD_BLE_WRITE_LOCAL_SPT_FEAT = 0x2004;
-    CMD_BLE_WRITE_RANDOM_ADDR = 0x2005;
-    CMD_BLE_WRITE_ADV_PARAMS = 0x2006;
-    CMD_BLE_READ_ADV_CHNL_TX_POWER = 0x2007;
-    CMD_BLE_WRITE_ADV_DATA = 0x2008;
-    CMD_BLE_WRITE_SCAN_RSP_DATA = 0x2009;
-    CMD_BLE_WRITE_ADV_ENABLE = 0x200A;
-    CMD_BLE_WRITE_SCAN_PARAMS = 0x200B;
-    CMD_BLE_WRITE_SCAN_ENABLE = 0x200C;
-    CMD_BLE_CREATE_LL_CONN = 0x200D;
-    CMD_BLE_CREATE_CONN_CANCEL = 0x200E;
-    CMD_BLE_READ_WHITE_LIST_SIZE = 0x200F;
-    CMD_BLE_CLEAR_WHITE_LIST = 0x2010;
-    CMD_BLE_ADD_WHITE_LIST = 0x2011;
-    CMD_BLE_REMOVE_WHITE_LIST = 0x2012;
-    CMD_BLE_UPD_LL_CONN_PARAMS = 0x2013;
-    CMD_BLE_SET_HOST_CHNL_CLASS = 0x2014;
-    CMD_BLE_READ_CHNL_MAP = 0x2015;
-    CMD_BLE_READ_REMOTE_FEAT = 0x2016;
-    CMD_BLE_ENCRYPT = 0x2017;
-    CMD_BLE_RAND = 0x2018;
-    CMD_BLE_START_ENC = 0x2019;
-    CMD_BLE_LTK_REQ_REPLY = 0x201A;
-    CMD_BLE_LTK_REQ_NEG_REPLY = 0x201B;
-    CMD_BLE_READ_SUPPORTED_STATES = 0x201C;
-    CMD_BLE_RECEIVER_TEST = 0x201D;
-    CMD_BLE_TRANSMITTER_TEST = 0x201E;
-    CMD_BLE_TEST_END = 0x201F;
-    CMD_BLE_RC_PARAM_REQ_REPLY = 0x2020;
-    CMD_BLE_RC_PARAM_REQ_NEG_REPLY = 0x2021;
-    CMD_BLE_SET_DATA_LENGTH = 0x2022;
-    CMD_BLE_READ_DEFAULT_DATA_LENGTH = 0x2023;
-    CMD_BLE_WRITE_DEFAULT_DATA_LENGTH = 0x2024;
-    CMD_BLE_GENERATE_DHKEY = 0x2026; // Not currently used in system/bt
-    CMD_BLE_ADD_DEV_RESOLVING_LIST = 0x2027;
-    CMD_BLE_RM_DEV_RESOLVING_LIST = 0x2028;
-    CMD_BLE_CLEAR_RESOLVING_LIST = 0x2029;
-    CMD_BLE_READ_RESOLVING_LIST_SIZE = 0x202A;
-    CMD_BLE_READ_RESOLVABLE_ADDR_PEER = 0x202B;
-    CMD_BLE_READ_RESOLVABLE_ADDR_LOCAL = 0x202C;
-    CMD_BLE_SET_ADDR_RESOLUTION_ENABLE = 0x202D;
-    CMD_BLE_SET_RAND_PRIV_ADDR_TIMOUT = 0x202E;
-    CMD_BLE_READ_MAXIMUM_DATA_LENGTH = 0x202F;
-    CMD_BLE_READ_PHY = 0x2030;
-    CMD_BLE_SET_DEFAULT_PHY = 0x2031;
-    CMD_BLE_SET_PHY = 0x2032;
-    CMD_BLE_ENH_RECEIVER_TEST = 0x2033;
-    CMD_BLE_ENH_TRANSMITTER_TEST = 0x2034;
-    CMD_BLE_SET_EXT_ADVERTISING_RANDOM_ADDRESS = 0x2035;
-    CMD_BLE_SET_EXT_ADVERTISING_PARAM = 0x2036;
-    CMD_BLE_SET_EXT_ADVERTISING_DATA = 0x2037;
-    CMD_BLE_SET_EXT_ADVERTISING_SCAN_RESP = 0x2038;
-    CMD_BLE_SET_EXT_ADVERTISING_ENABLE = 0x2039;
-    CMD_BLE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 0x203A;
-    CMD_BLE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 0x203B;
-    CMD_BLE_REMOVE_ADVERTISING_SET = 0x203C;
-    CMD_BLE_CLEAR_ADVERTISING_SETS = 0x203D;
-    CMD_BLE_SET_PERIODIC_ADVERTISING_PARAM = 0x203E;
-    CMD_BLE_SET_PERIODIC_ADVERTISING_DATA = 0x203F;
-    CMD_BLE_SET_PERIODIC_ADVERTISING_ENABLE = 0x2040;
-    CMD_BLE_SET_EXTENDED_SCAN_PARAMETERS = 0x2041;
-    CMD_BLE_SET_EXTENDED_SCAN_ENABLE = 0x2042;
-    CMD_BLE_EXTENDED_CREATE_CONNECTION = 0x2043;
-    CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC = 0x2044;
-    CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 0x2045;
-    CMD_BLE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 0x2046;
-    CMD_BLE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 0x2047;
-    CMD_BLE_RM_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 0x2048;
-    CMD_BLE_CLEAR_PERIODIC_ADVERTISING_LIST = 0x2049;
-    CMD_BLE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 0x204A;
-    CMD_BLE_READ_TRANSMIT_POWER = 0x204B;
-    CMD_BLE_READ_RF_COMPENS_POWER = 0x204C;
-    CMD_BLE_WRITE_RF_COMPENS_POWER = 0x204D;
-    CMD_BLE_SET_PRIVACY_MODE = 0x204E;
-    // Vendor specific commands 0xFC00 and above
-    // Android vendor specific commands defined in
-    // https://source.android.com/devices/bluetooth/hci_requirements#vendor-specific-capabilities
-    CMD_BLE_VENDOR_CAP = 0xFD53;
-    CMD_BLE_MULTI_ADV = 0xFD54;
-    CMD_BLE_BATCH_SCAN = 0xFD56;
-    CMD_BLE_ADV_FILTER = 0xFD57;
-    CMD_BLE_TRACK_ADV = 0xFD58;
-    CMD_BLE_ENERGY_INFO = 0xFD59;
-    CMD_BLE_EXTENDED_SCAN_PARAMS = 0xFD5A;
-    CMD_CONTROLLER_DEBUG_INFO = 0xFD5B;
-    CMD_CONTROLLER_A2DP_OPCODE = 0xFD5D;
-    CMD_BRCM_SET_ACL_PRIORITY = 0xFC57;
-    // Other vendor specific commands below here
-}
-
-// HCI event codes from the Bluetooth 5.0 specification Vol 2, Part 7, Section 7
-// Original definition: system/bt/stack/include/hcidefs.h
-enum EventEnum {
-    // Event is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
-    EVT_UNKNOWN = 0xFFF;
-    EVT_INQUIRY_COMP = 0x01;
-    EVT_INQUIRY_RESULT = 0x02;
-    EVT_CONNECTION_COMP = 0x03;
-    EVT_CONNECTION_REQUEST = 0x04;
-    EVT_DISCONNECTION_COMP = 0x05;
-    EVT_AUTHENTICATION_COMP = 0x06;
-    EVT_RMT_NAME_REQUEST_COMP = 0x07;
-    EVT_ENCRYPTION_CHANGE = 0x08;
-    EVT_CHANGE_CONN_LINK_KEY = 0x09;
-    EVT_MASTER_LINK_KEY_COMP = 0x0A;
-    EVT_READ_RMT_FEATURES_COMP = 0x0B;
-    EVT_READ_RMT_VERSION_COMP = 0x0C;
-    EVT_QOS_SETUP_COMP = 0x0D;
-    EVT_COMMAND_COMPLETE = 0x0E;
-    EVT_COMMAND_STATUS = 0x0F;
-    EVT_HARDWARE_ERROR = 0x10;
-    EVT_FLUSH_OCCURRED = 0x11;
-    EVT_ROLE_CHANGE = 0x12;
-    EVT_NUM_COMPL_DATA_PKTS = 0x13;
-    EVT_MODE_CHANGE = 0x14;
-    EVT_RETURN_LINK_KEYS = 0x15;
-    EVT_PIN_CODE_REQUEST = 0x16;
-    EVT_LINK_KEY_REQUEST = 0x17;
-    EVT_LINK_KEY_NOTIFICATION = 0x18;
-    EVT_LOOPBACK_COMMAND = 0x19;
-    EVT_DATA_BUF_OVERFLOW = 0x1A;
-    EVT_MAX_SLOTS_CHANGED = 0x1B;
-    EVT_READ_CLOCK_OFF_COMP = 0x1C;
-    EVT_CONN_PKT_TYPE_CHANGE = 0x1D;
-    EVT_QOS_VIOLATION = 0x1E;
-    EVT_PAGE_SCAN_MODE_CHANGE = 0x1F; // Deprecated
-    EVT_PAGE_SCAN_REP_MODE_CHNG = 0x20;
-    EVT_FLOW_SPECIFICATION_COMP = 0x21;
-    EVT_INQUIRY_RSSI_RESULT = 0x22;
-    EVT_READ_RMT_EXT_FEATURES_COMP = 0x23;
-    EVT_ESCO_CONNECTION_COMP = 0x2C;
-    EVT_ESCO_CONNECTION_CHANGED = 0x2D;
-    EVT_SNIFF_SUB_RATE = 0x2E;
-    EVT_EXTENDED_INQUIRY_RESULT = 0x2F;
-    EVT_ENCRYPTION_KEY_REFRESH_COMP = 0x30;
-    EVT_IO_CAPABILITY_REQUEST = 0x31;
-    EVT_IO_CAPABILITY_RESPONSE = 0x32;
-    EVT_USER_CONFIRMATION_REQUEST = 0x33;
-    EVT_USER_PASSKEY_REQUEST = 0x34;
-    EVT_REMOTE_OOB_DATA_REQUEST = 0x35;
-    EVT_SIMPLE_PAIRING_COMPLETE = 0x36;
-    EVT_LINK_SUPER_TOUT_CHANGED = 0x38;
-    EVT_ENHANCED_FLUSH_COMPLETE = 0x39;
-    EVT_USER_PASSKEY_NOTIFY = 0x3B;
-    EVT_KEYPRESS_NOTIFY = 0x3C;
-    EVT_RMT_HOST_SUP_FEAT_NOTIFY = 0x3D;
-    EVT_BLE_META = 0x3E;
-    EVT_PHYSICAL_LINK_COMP = 0x40;
-    EVT_CHANNEL_SELECTED = 0x41;
-    EVT_DISC_PHYSICAL_LINK_COMP = 0x42;
-    EVT_PHY_LINK_LOSS_EARLY_WARNING = 0x43;
-    EVT_PHY_LINK_RECOVERY = 0x44;
-    EVT_LOGICAL_LINK_COMP = 0x45;
-    EVT_DISC_LOGICAL_LINK_COMP = 0x46;
-    EVT_FLOW_SPEC_MODIFY_COMP = 0x47;
-    EVT_NUM_COMPL_DATA_BLOCKS = 0x48;
-    EVT_AMP_TEST_START = 0x49; // Not currently used in system/bt
-    EVT_AMP_TEST_END = 0x4A; // Not currently used in system/bt
-    EVT_AMP_RECEIVER_RPT = 0x4B; // Not currently used in system/bt
-    EVT_SHORT_RANGE_MODE_COMPLETE = 0x4C;
-    EVT_AMP_STATUS_CHANGE = 0x4D;
-    EVT_SET_TRIGGERED_CLOCK_CAPTURE = 0x4E;
-    EVT_SYNC_TRAIN_CMPL = 0x4F; // Not currently used in system/bt
-    EVT_SYNC_TRAIN_RCVD = 0x50; // Not currently used in system/bt
-    EVT_CONNLESS_SLAVE_BROADCAST_RCVD = 0x51; // Not currently used in system/bt
-    EVT_CONNLESS_SLAVE_BROADCAST_TIMEOUT = 0x52; // Not currently used in system/bt
-    EVT_TRUNCATED_PAGE_CMPL = 0x53; // Not currently used in system/bt
-    EVT_SLAVE_PAGE_RES_TIMEOUT = 0x54; // Not currently used in system/bt
-    EVT_CONNLESS_SLAVE_BROADCAST_CHNL_MAP_CHANGE = 0x55; // Not currently used in system/bt
-    EVT_INQUIRY_RES_NOTIFICATION = 0x56; // Not currently used in system/bt
-    EVT_AUTHED_PAYLOAD_TIMEOUT = 0x57; // Not currently used in system/bt
-    EVT_SAM_STATUS_CHANGE = 0x58; // Not currently used in system/bt
-}
-
-// Bluetooth low energy related meta event codes
-// from the Bluetooth 5.0 specification Vol 2, Part E, Section 7.7.65
-// Original definition: system/bt/stack/include/hcidefs.h
-enum BleMetaEventEnum {
-    // BLE meta event code is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
-    BLE_EVT_UNKNOWN = 0xFFF;
-    BLE_EVT_CONN_COMPLETE_EVT = 0x01;
-    BLE_EVT_ADV_PKT_RPT_EVT = 0x02;
-    BLE_EVT_LL_CONN_PARAM_UPD_EVT = 0x03;
-    BLE_EVT_READ_REMOTE_FEAT_CMPL_EVT = 0x04;
-    BLE_EVT_LTK_REQ_EVT = 0x05;
-    BLE_EVT_RC_PARAM_REQ_EVT = 0x06;
-    BLE_EVT_DATA_LENGTH_CHANGE_EVT = 0x07;
-    BLE_EVT_READ_LOCAL_P256_PUB_KEY = 0x08; // Not currently used in system/bt
-    BLE_EVT_GEN_DHKEY_CMPL = 0x09; // Not currently used in system/bt
-    BLE_EVT_ENHANCED_CONN_COMPLETE_EVT = 0x0a;
-    BLE_EVT_DIRECT_ADV_EVT = 0x0b;
-    BLE_EVT_PHY_UPDATE_COMPLETE_EVT = 0x0c;
-    BLE_EVT_EXTENDED_ADVERTISING_REPORT_EVT = 0x0D;
-    BLE_EVT_PERIODIC_ADV_SYNC_EST_EVT = 0x0E;
-    BLE_EVT_PERIODIC_ADV_REPORT_EVT = 0x0F;
-    BLE_EVT_PERIODIC_ADV_SYNC_LOST_EVT = 0x10;
-    BLE_EVT_SCAN_TIMEOUT_EVT = 0x11;
-    BLE_EVT_ADVERTISING_SET_TERMINATED_EVT = 0x12;
-    BLE_EVT_SCAN_REQ_RX_EVT = 0x13;
-    BLE_EVT_CHNL_SELECTION_ALGORITHM = 0x14; // Not currently used in system/bt
-}
-
-// HCI status code from the Bluetooth 5.0 specification Vol 2, Part D.
-// Original definition: system/bt/stack/include/hcidefs.h
-enum StatusEnum {
-    // Status is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
-    STATUS_UNKNOWN = 0xFFF;
-    STATUS_SUCCESS = 0x00;
-    STATUS_ILLEGAL_COMMAND = 0x01;
-    STATUS_NO_CONNECTION = 0x02;
-    STATUS_HW_FAILURE = 0x03;
-    STATUS_PAGE_TIMEOUT = 0x04;
-    STATUS_AUTH_FAILURE = 0x05;
-    STATUS_KEY_MISSING = 0x06;
-    STATUS_MEMORY_FULL = 0x07;
-    STATUS_CONNECTION_TOUT = 0x08;
-    STATUS_MAX_NUM_OF_CONNECTIONS = 0x09;
-    STATUS_MAX_NUM_OF_SCOS = 0x0A;
-    STATUS_CONNECTION_EXISTS = 0x0B;
-    STATUS_COMMAND_DISALLOWED = 0x0C;
-    STATUS_HOST_REJECT_RESOURCES = 0x0D;
-    STATUS_HOST_REJECT_SECURITY = 0x0E;
-    STATUS_HOST_REJECT_DEVICE = 0x0F;
-    STATUS_HOST_TIMEOUT = 0x10;
-    STATUS_UNSUPPORTED_VALUE = 0x11;
-    STATUS_ILLEGAL_PARAMETER_FMT = 0x12;
-    STATUS_PEER_USER = 0x13;
-    STATUS_PEER_LOW_RESOURCES = 0x14;
-    STATUS_PEER_POWER_OFF = 0x15;
-    STATUS_CONN_CAUSE_LOCAL_HOST = 0x16;
-    STATUS_REPEATED_ATTEMPTS = 0x17;
-    STATUS_PAIRING_NOT_ALLOWED = 0x18;
-    STATUS_UNKNOWN_LMP_PDU = 0x19;
-    STATUS_UNSUPPORTED_REM_FEATURE = 0x1A;
-    STATUS_SCO_OFFSET_REJECTED = 0x1B;
-    STATUS_SCO_INTERVAL_REJECTED = 0x1C;
-    STATUS_SCO_AIR_MODE = 0x1D;
-    STATUS_INVALID_LMP_PARAM = 0x1E;
-    STATUS_UNSPECIFIED = 0x1F;
-    STATUS_UNSUPPORTED_LMP_FEATURE = 0x20;
-    STATUS_ROLE_CHANGE_NOT_ALLOWED = 0x21;
-    STATUS_LMP_RESPONSE_TIMEOUT = 0x22;
-    STATUS_LMP_STATUS_TRANS_COLLISION = 0x23;
-    STATUS_LMP_PDU_NOT_ALLOWED = 0x24;
-    STATUS_ENCRY_MODE_NOT_ACCEPTABLE = 0x25;
-    STATUS_UNIT_KEY_USED = 0x26;
-    STATUS_QOS_NOT_SUPPORTED = 0x27;
-    STATUS_INSTANT_PASSED = 0x28;
-    STATUS_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29;
-    STATUS_DIFF_TRANSACTION_COLLISION = 0x2A;
-    STATUS_UNDEFINED_0x2B = 0x2B; // Not used
-    STATUS_QOS_UNACCEPTABLE_PARAM = 0x2C;
-    STATUS_QOS_REJECTED = 0x2D;
-    STATUS_CHAN_CLASSIF_NOT_SUPPORTED = 0x2E;
-    STATUS_INSUFFCIENT_SECURITY = 0x2F;
-    STATUS_PARAM_OUT_OF_RANGE = 0x30;
-    STATUS_UNDEFINED_0x31 = 0x31; // Not used
-    STATUS_ROLE_SWITCH_PENDING = 0x32;
-    STATUS_UNDEFINED_0x33 = 0x33;
-    STATUS_RESERVED_SLOT_VIOLATION = 0x34;
-    STATUS_ROLE_SWITCH_FAILED = 0x35;
-    STATUS_INQ_RSP_DATA_TOO_LARGE = 0x36;
-    STATUS_SIMPLE_PAIRING_NOT_SUPPORTED = 0x37;
-    STATUS_HOST_BUSY_PAIRING = 0x38;
-    STATUS_REJ_NO_SUITABLE_CHANNEL = 0x39;
-    STATUS_CONTROLLER_BUSY = 0x3A;
-    STATUS_UNACCEPT_CONN_INTERVAL = 0x3B;
-    STATUS_ADVERTISING_TIMEOUT = 0x3C;
-    STATUS_CONN_TOUT_DUE_TO_MIC_FAILURE = 0x3D;
-    STATUS_CONN_FAILED_ESTABLISHMENT = 0x3E;
-    STATUS_MAC_CONNECTION_FAILED = 0x3F;
-    STATUS_LT_ADDR_ALREADY_IN_USE = 0x40;
-    STATUS_LT_ADDR_NOT_ALLOCATED = 0x41;
-    STATUS_CLB_NOT_ENABLED = 0x42;
-    STATUS_CLB_DATA_TOO_BIG = 0x43;
-    STATUS_OPERATION_CANCELED_BY_HOST = 0x44; // Not currently used in system/bt
-}
-
-enum BqrIdEnum {
-    BQR_ID_UNKNOWN = 0x00;
-    BQR_ID_MONITOR_MODE = 0x01;
-    BQR_ID_APPROACH_LSTO = 0x02;
-    BQR_ID_A2DP_AUDIO_CHOPPY = 0x03;
-    BQR_ID_SCO_VOICE_CHOPPY = 0x04;
-}
-
-enum BqrPacketTypeEnum {
-    BQR_PACKET_TYPE_UNKNOWN = 0x00;
-    BQR_PACKET_TYPE_ID = 0x01;
-    BQR_PACKET_TYPE_NULL = 0x02;
-    BQR_PACKET_TYPE_POLL = 0x03;
-    BQR_PACKET_TYPE_FHS = 0x04;
-    BQR_PACKET_TYPE_HV1 = 0x05;
-    BQR_PACKET_TYPE_HV2 = 0x06;
-    BQR_PACKET_TYPE_HV3 = 0x07;
-    BQR_PACKET_TYPE_DV = 0x08;
-    BQR_PACKET_TYPE_EV3 = 0x09;
-    BQR_PACKET_TYPE_EV4 = 0x0A;
-    BQR_PACKET_TYPE_EV5 = 0x0B;
-    BQR_PACKET_TYPE_2EV3 = 0x0C;
-    BQR_PACKET_TYPE_2EV5 = 0x0D;
-    BQR_PACKET_TYPE_3EV3 = 0x0E;
-    BQR_PACKET_TYPE_3EV5 = 0x0F;
-    BQR_PACKET_TYPE_DM1 = 0x10;
-    BQR_PACKET_TYPE_DH1 = 0x11;
-    BQR_PACKET_TYPE_DM3 = 0x12;
-    BQR_PACKET_TYPE_DH3 = 0x13;
-    BQR_PACKET_TYPE_DM5 = 0x14;
-    BQR_PACKET_TYPE_DH5 = 0x15;
-    BQR_PACKET_TYPE_AUX1 = 0x16;
-    BQR_PACKET_TYPE_2DH1 = 0x17;
-    BQR_PACKET_TYPE_2DH3 = 0x18;
-    BQR_PACKET_TYPE_2DH5 = 0x19;
-    BQR_PACKET_TYPE_3DH1 = 0x1A;
-    BQR_PACKET_TYPE_3DH3 = 0x1B;
-    BQR_PACKET_TYPE_3DH5 = 0x1C;
-}
diff --git a/core/proto/android/bluetooth/hfp/enums.proto b/core/proto/android/bluetooth/hfp/enums.proto
deleted file mode 100644
index d286e4b..0000000
--- a/core/proto/android/bluetooth/hfp/enums.proto
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.bluetooth.hfp;
-
-option java_outer_classname = "BluetoothHfpProtoEnums";
-option java_multiple_files = true;
-
-enum ScoCodec {
-    SCO_CODEC_UNKNOWN = 0;
-    SCO_CODEC_CVSD = 1;
-    // Default codec behind Wide Band Speech
-    SCO_CODEC_MSBC = 2;
-}
\ No newline at end of file
diff --git a/core/proto/android/bluetooth/smp/enums.proto b/core/proto/android/bluetooth/smp/enums.proto
deleted file mode 100644
index c6747b7..0000000
--- a/core/proto/android/bluetooth/smp/enums.proto
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.bluetooth.smp;
-
-option java_outer_classname = "BluetoothSmpProtoEnums";
-option java_multiple_files = true;
-
-// SMP Pairing command codes
-enum CommandEnum {
-    CMD_UNKNOWN = 0x00;
-    CMD_PAIRING_REQUEST = 0x01;
-    CMD_PAIRING_RESPONSE = 0x02;
-    CMD_PAIRING_CONFIRM = 0x03;
-    CMD_PAIRING_RANDOM = 0x04;
-    CMD_PAIRING_FAILED = 0x05;
-    CMD_ENCRYPTION_INFON = 0x06;
-    CMD_MASTER_IDENTIFICATION = 0x07;
-    CMD_IDENTITY_INFO = 0x08;
-    CMD_IDENTITY_ADDR_INFO = 0x09;
-    CMD_SIGNING_INFO = 0x0A;
-    CMD_SECURITY_REQUEST = 0x0B;
-    CMD_PAIRING_PUBLIC_KEY = 0x0C;
-    CMD_PAIRING_DHKEY_CHECK = 0x0D;
-    CMD_PAIRING_KEYPRESS_INFO = 0x0E;
-}
-
-enum PairingFailReasonEnum {
-    PAIRING_FAIL_REASON_RESERVED = 0x00;
-    PAIRING_FAIL_REASON_PASSKEY_ENTRY = 0x01;
-    PAIRING_FAIL_REASON_OOB = 0x02;
-    PAIRING_FAIL_REASON_AUTH_REQ = 0x03;
-    PAIRING_FAIL_REASON_CONFIRM_VALUE = 0x04;
-    PAIRING_FAIL_REASON_PAIR_NOT_SUPPORT = 0x05;
-    PAIRING_FAIL_REASON_ENC_KEY_SIZE = 0x06;
-    PAIRING_FAIL_REASON_INVALID_CMD = 0x07;
-    PAIRING_FAIL_REASON_UNSPECIFIED = 0x08;
-    PAIRING_FAIL_REASON_REPEATED_ATTEMPTS = 0x09;
-    PAIRING_FAIL_REASON_INVALID_PARAMETERS = 0x0A;
-    PAIRING_FAIL_REASON_DHKEY_CHK = 0x0B;
-    PAIRING_FAIL_REASON_NUMERIC_COMPARISON = 0x0C;
-    PAIRING_FAIL_REASON_CLASSIC_PAIRING_IN_PROGR = 0x0D;
-    PAIRING_FAIL_REASON_XTRANS_DERIVE_NOT_ALLOW = 0x0E;
-}
\ No newline at end of file
diff --git a/core/proto/android/debug/enums.proto b/core/proto/android/debug/enums.proto
deleted file mode 100644
index 6747bb7..0000000
--- a/core/proto/android/debug/enums.proto
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.debug;
-
-option java_outer_classname = "AdbProtoEnums";
-option java_multiple_files = true;
-
-/**
- * adb connection state used to track adb connection changes in AdbDebuggingManager.java.
- */
-enum AdbConnectionStateEnum {
-    UNKNOWN = 0;
-
-    /**
-     * The adb connection is waiting for approval from the user.
-     */
-    AWAITING_USER_APPROVAL = 1;
-
-    /**
-     * The user allowed the adb connection from the system.
-     */
-    USER_ALLOWED = 2;
-
-    /**
-     * The user denied the adb connection from the system.
-     */
-    USER_DENIED = 3;
-
-    /**
-     * The adb connection was automatically allowed without user interaction due to the system
-     * being previously allowed by the user with the 'always allow' option selected, and the adb
-     * grant has not yet expired.
-     */
-    AUTOMATICALLY_ALLOWED = 4;
-
-    /**
-     * An empty or invalid base64 encoded key was provided to the framework; the connection was
-     * automatically denied.
-     */
-    DENIED_INVALID_KEY = 5;
-
-    /**
-     * vold decrypt has not yet occurred; the connection was automatically denied.
-     */
-    DENIED_VOLD_DECRYPT = 6;
-
-    /**
-     * The adb session has been disconnected.
-     */
-    DISCONNECTED = 7;
-}
-
diff --git a/core/proto/android/hardware/biometrics/enums.proto b/core/proto/android/hardware/biometrics/enums.proto
deleted file mode 100644
index f2e0638..0000000
--- a/core/proto/android/hardware/biometrics/enums.proto
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.hardware.biometrics;
-
-option java_outer_classname = "BiometricsProtoEnums";
-option java_multiple_files = true;
-
-// Logging constants for <Biometric>Service and BiometricService
-
-enum ModalityEnum {
-    MODALITY_UNKNOWN = 0;
-    MODALITY_FINGERPRINT = 1;   // 1 << 0
-    MODALITY_IRIS = 2;          // 1 << 1
-    MODALITY_FACE = 4;          // 1 << 2
-}
-
-enum ClientEnum {
-    CLIENT_UNKNOWN = 0;
-    CLIENT_KEYGUARD = 1;
-    CLIENT_BIOMETRIC_PROMPT = 2;
-    CLIENT_FINGERPRINT_MANAGER = 3; // Deprecated API before BiometricPrompt was introduced
-}
-
-enum ActionEnum {
-    ACTION_UNKNOWN = 0;
-    ACTION_ENROLL = 1;
-    ACTION_AUTHENTICATE = 2;
-    ACTION_ENUMERATE = 3;
-    ACTION_REMOVE = 4;
-}
-
-enum IssueEnum {
-    ISSUE_UNKNOWN = 0;
-    // When a biometric HAL has crashed.
-    ISSUE_HAL_DEATH = 1;
-    // When Android Framework has a template that doesn't exist in the HAL. The framework
-    // is expected to remove its template to stay in sync with the HAL.
-    ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK = 2;
-    // When the HAL has a template that doesn't exist in Android Framework. The framework
-    // is expected to notify the HAL to remove this template to stay in sync with the framework.
-    ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL = 3;
-    // When the HAL has not sent ERROR_CANCELED within the specified timeout.
-    ISSUE_CANCEL_TIMED_OUT = 4;
-}
\ No newline at end of file
diff --git a/core/proto/android/hardware/sensor/assist/enums.proto b/core/proto/android/hardware/sensor/assist/enums.proto
deleted file mode 100644
index 012dcb2..0000000
--- a/core/proto/android/hardware/sensor/assist/enums.proto
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.hardware.sensor.assist;
-
-option java_outer_classname = "AssistGestureProtoEnums";
-option java_multiple_files = true;
-
-enum AssistGestureStageEnum {
-    ASSIST_GESTURE_STAGE_UNKNOWN = 0;
-    ASSIST_GESTURE_STAGE_PROGRESS = 1;
-    ASSIST_GESTURE_STAGE_PRIMED = 2;
-    ASSIST_GESTURE_STAGE_DETECTED = 3;
-}
-
-enum AssistGestureFeedbackEnum {
-    ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
-    ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
-    ASSIST_GESTURE_FEEDBACK_USED = 2;
-}
\ No newline at end of file
diff --git a/core/proto/android/net/networkcapabilities.proto b/core/proto/android/net/networkcapabilities.proto
deleted file mode 100644
index be0cad1..0000000
--- a/core/proto/android/net/networkcapabilities.proto
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.net;
-
-option java_multiple_files = true;
-
-import "frameworks/base/core/proto/android/privacy.proto";
-
-/**
- * An android.net.NetworkCapabilities object.
- */
-message NetworkCapabilitiesProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    enum Transport {
-        // Indicates this network uses a Cellular transport.
-        TRANSPORT_CELLULAR = 0;
-        // Indicates this network uses a Wi-Fi transport.
-        TRANSPORT_WIFI = 1;
-        // Indicates this network uses a Bluetooth transport.
-        TRANSPORT_BLUETOOTH = 2;
-        // Indicates this network uses an Ethernet transport.
-        TRANSPORT_ETHERNET = 3;
-        // Indicates this network uses a VPN transport.
-        TRANSPORT_VPN = 4;
-        // Indicates this network uses a Wi-Fi Aware transport.
-        TRANSPORT_WIFI_AWARE = 5;
-        // Indicates this network uses a LoWPAN transport.
-        TRANSPORT_LOWPAN = 6;
-    }
-    repeated Transport transports = 1;
-
-    enum NetCapability {
-        // Indicates this is a network that has the ability to reach the
-        // carrier's MMSC for sending and receiving MMS messages.
-        NET_CAPABILITY_MMS = 0;
-        // Indicates this is a network that has the ability to reach the
-        // carrier's SUPL server, used to retrieve GPS information.
-        NET_CAPABILITY_SUPL = 1;
-        // Indicates this is a network that has the ability to reach the
-        // carrier's DUN or tethering gateway.
-        NET_CAPABILITY_DUN = 2;
-        // Indicates this is a network that has the ability to reach the
-        // carrier's FOTA portal, used for over the air updates.
-        NET_CAPABILITY_FOTA = 3;
-        // Indicates this is a network that has the ability to reach the
-        // carrier's IMS servers, used for network registration and signaling.
-        NET_CAPABILITY_IMS = 4;
-        // Indicates this is a network that has the ability to reach the
-        // carrier's CBS servers, used for carrier specific services.
-        NET_CAPABILITY_CBS = 5;
-        // Indicates this is a network that has the ability to reach a Wi-Fi
-        // direct peer.
-        NET_CAPABILITY_WIFI_P2P = 6;
-        // Indicates this is a network that has the ability to reach a carrier's
-        // Initial Attach servers.
-        NET_CAPABILITY_IA = 7;
-        // Indicates this is a network that has the ability to reach a carrier's
-        // RCS servers, used for Rich Communication Services.
-        NET_CAPABILITY_RCS = 8;
-        // Indicates this is a network that has the ability to reach a carrier's
-        // XCAP servers, used for configuration and control.
-        NET_CAPABILITY_XCAP = 9;
-        // Indicates this is a network that has the ability to reach a carrier's
-        // Emergency IMS servers or other services, used for network signaling
-        // during emergency calls.
-        NET_CAPABILITY_EIMS = 10;
-        // Indicates that this network is unmetered.
-        NET_CAPABILITY_NOT_METERED = 11;
-        // Indicates that this network should be able to reach the internet.
-        NET_CAPABILITY_INTERNET = 12;
-        // Indicates that this network is available for general use. If this is
-        // not set applications should not attempt to communicate on this
-        // network. Note that this is simply informative and not enforcement -
-        // enforcement is handled via other means. Set by default.
-        NET_CAPABILITY_NOT_RESTRICTED = 13;
-        // Indicates that the user has indicated implicit trust of this network.
-        // This generally means it's a sim-selected carrier, a plugged in
-        // ethernet, a paired BT device or a wifi the user asked to connect to.
-        // Untrusted networks are probably limited to unknown wifi AP. Set by
-        // default.
-        NET_CAPABILITY_TRUSTED = 14;
-        // Indicates that this network is not a VPN.  This capability is set by
-        // default and should be explicitly cleared for VPN networks.
-        NET_CAPABILITY_NOT_VPN = 15;
-        // Indicates that connectivity on this network was successfully
-        // validated. For example, for a network with NET_CAPABILITY_INTERNET,
-        // it means that Internet connectivity was successfully detected.
-        NET_CAPABILITY_VALIDATED = 16;
-        // Indicates that this network was found to have a captive portal in
-        // place last time it was probed.
-        NET_CAPABILITY_CAPTIVE_PORTAL = 17;
-        // Indicates that this network is not roaming.
-        NET_CAPABILITY_NOT_ROAMING = 18;
-        // Indicates that this network is available for use by apps, and not a
-        // network that is being kept up in the background to facilitate fast
-        // network switching.
-        NET_CAPABILITY_FOREGROUND = 19;
-    }
-    repeated NetCapability capabilities = 2;
-
-    // Passive link bandwidth. This is a rough guide of the expected peak
-    // bandwidth for the first hop on the given transport.  It is not measured,
-    // but may take into account link parameters (Radio technology, allocated
-    // channels, etc).
-    optional int32 link_up_bandwidth_kbps = 3;
-    optional int32 link_down_bandwidth_kbps = 4;
-
-    optional string network_specifier = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
-
-    // True if this object specifies a signal strength.
-    optional bool can_report_signal_strength = 6;
-    // This is a signed integer, and higher values indicate better signal. The
-    // exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
-    // Only valid if can_report_signal_strength is true.
-    optional sint32 signal_strength = 7;
-}
diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto
index b35a020..6794c8c 100644
--- a/core/proto/android/net/networkrequest.proto
+++ b/core/proto/android/net/networkrequest.proto
@@ -20,8 +20,8 @@
 
 option java_multiple_files = true;
 
-import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/net/networkcapabilities.proto";
 
 /**
  * An android.net.NetworkRequest object.
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 892ebf7..7d68a0d 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -19,10 +19,10 @@
 
 package android.os;
 
-import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/os/powermanager.proto";
-import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/app/job/enums.proto";
+import "frameworks/proto_logging/stats/enums/telephony/enums.proto";
 
 message BatteryStatsProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto
deleted file mode 100644
index 566861b..0000000
--- a/core/proto/android/os/enums.proto
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.os;
-
-option java_outer_classname = "OsProtoEnums";
-option java_multiple_files = true;
-
-// These constants are defined in hardware/interfaces/health/1.0/types.hal
-// They are primarily used by android/os/BatteryManager.java.
-enum BatteryHealthEnum {
-    BATTERY_HEALTH_INVALID = 0;
-    BATTERY_HEALTH_UNKNOWN = 1;
-    BATTERY_HEALTH_GOOD = 2;
-    BATTERY_HEALTH_OVERHEAT = 3;
-    BATTERY_HEALTH_DEAD = 4;
-    BATTERY_HEALTH_OVER_VOLTAGE = 5;
-    BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
-    BATTERY_HEALTH_COLD = 7;
-}
-
-// Plug states, primarily used by android/os/BatteryManager.java.
-enum BatteryPluggedStateEnum {
-    // Note that NONE is not in BatteryManager.java's constants.
-    BATTERY_PLUGGED_NONE = 0;
-    // Power source is an AC charger.
-    BATTERY_PLUGGED_AC = 1;
-    // Power source is a USB port.
-    BATTERY_PLUGGED_USB = 2;
-    // Power source is wireless.
-    BATTERY_PLUGGED_WIRELESS = 4;
-}
-
-// These constants are defined in hardware/interfaces/health/1.0/types.hal
-// They are primarily used by android/os/BatteryManager.java.
-enum BatteryStatusEnum {
-    BATTERY_STATUS_INVALID = 0;
-    BATTERY_STATUS_UNKNOWN = 1;
-    BATTERY_STATUS_CHARGING = 2;
-    BATTERY_STATUS_DISCHARGING = 3;
-    BATTERY_STATUS_NOT_CHARGING = 4;
-    BATTERY_STATUS_FULL = 5;
-}
-
-// These constants are defined in hardware/interfaces/thermal/1.0/types.hal
-// and in hardware/interfaces/thermal/2.0/types.hal
-// They are primarily used by android/os/HardwarePropertiesManager.java.
-// Any change to the types in the thermal hal should be made here as well.
-enum TemperatureTypeEnum {
-    TEMPERATURE_TYPE_UNKNOWN = -1;
-    TEMPERATURE_TYPE_CPU = 0;
-    TEMPERATURE_TYPE_GPU = 1;
-    TEMPERATURE_TYPE_BATTERY = 2;
-    TEMPERATURE_TYPE_SKIN = 3;
-    TEMPERATURE_TYPE_USB_PORT = 4;
-    TEMPERATURE_TYPE_POWER_AMPLIFIER = 5;
-
-    // Battery Charge Limit - virtual thermal sensors.
-    TEMPERATURE_TYPE_BCL_VOLTAGE = 6;
-    TEMPERATURE_TYPE_BCL_CURRENT = 7;
-    TEMPERATURE_TYPE_BCL_PERCENTAGE = 8;
-
-    // Neural Processing Unit.
-    TEMPERATURE_TYPE_NPU = 9;
-}
-
-// Device throttling severity
-// These constants are defined in hardware/interfaces/thermal/2.0/types.hal.
-// Any change to the types in the thermal hal should be made here as well.
-enum ThrottlingSeverityEnum {
-    // Not under throttling.
-    NONE = 0;
-    // Light throttling where UX is not impacted.
-    LIGHT = 1;
-    // Moderate throttling where UX is not largely impacted.
-    MODERATE = 2;
-    // Severe throttling where UX is largely impacted.
-    // Similar to 1.0 throttlingThreshold.
-    SEVERE = 3;
-    // Platform has done everything to reduce power.
-    CRITICAL = 4;
-    // Key components in platform are shutting down due to thermal condition.
-    // Device functionalities will be limited.
-    EMERGENCY = 5;
-    // Need shutdown immediately.
-    SHUTDOWN = 6;
-};
-
-// Device cooling device types.
-// These constants are defined in hardware/interfaces/thermal/2.0/types.hal.
-// Any change to the types in the thermal hal should be made here as well.
-enum CoolingTypeEnum {
-    FAN = 0;
-    BATTERY = 1;
-    CPU = 2;
-    GPU = 3;
-    MODEM = 4;
-    NPU = 5;
-    COMPONENT = 6;
-};
-
-// Wakelock types, primarily used by android/os/PowerManager.java.
-enum WakeLockLevelEnum {
-    // NOTE: Wake lock levels were previously defined as a bit field, except
-    // that only a few combinations were actually supported so the bit field
-    // was removed. This explains why the numbering scheme is so odd. If
-    // adding a new wake lock level, any unused value can be used.
-
-    // Ensures that the CPU is running; the screen and keyboard backlight
-    // will be allowed to go off.
-    PARTIAL_WAKE_LOCK = 1;
-
-    // Ensures that the screen is on (but may be dimmed); the keyboard
-    // backlight will be allowed to go off. If the user presses the power
-    // button, then the SCREEN_DIM_WAKE_LOCK will be implicitly released by
-    // the system, causing both the screen and the CPU to be turned off.
-    SCREEN_DIM_WAKE_LOCK = 6 [deprecated = true];
-
-    // Ensures that the screen is on at full brightness; the keyboard
-    // backlight will be allowed to go off. If the user presses the power
-    // button, then the SCREEN_BRIGHT_WAKE_LOCK will be implicitly released
-    // by the system, causing both the screen and the CPU to be turned off.
-    SCREEN_BRIGHT_WAKE_LOCK = 10 [deprecated = true];
-
-    // Ensures that the screen and keyboard backlight are on at full
-    // brightness. If the user presses the power button, then the
-    // FULL_WAKE_LOCK will be implicitly released by the system, causing
-    // both the screen and the CPU to be turned off.
-    FULL_WAKE_LOCK = 26 [deprecated = true];
-
-    // Turns the screen off when the proximity sensor activates. If the
-    // proximity sensor detects that an object is nearby, the screen turns
-    // off immediately. Shortly after the object moves away, the screen
-    // turns on again.
-    // A proximity wake lock does not prevent the device from falling asleep
-    // unlike FULL_WAKE_LOCK, SCREEN_BRIGHT_WAKE_LOCK and
-    // SCREEN_DIM_WAKE_LOCK. If there is no user activity and no other wake
-    // locks are held, then the device will fall asleep (and lock) as usual.
-    // However, the device will not fall asleep while the screen has been
-    // turned off by the proximity sensor because it effectively counts as
-    // ongoing user activity.
-    PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
-
-    // Put the screen in a low power state and allow the CPU to suspend if
-    // no other wake locks are held. This is used by the dream manager to
-    // implement doze mode. It currently has no effect unless the power
-    // manager is in the dozing state.
-    DOZE_WAKE_LOCK = 64;
-
-    // Keep the device awake enough to allow drawing to occur. This is used
-    // by the window manager to allow applications to draw while the system
-    // is dozing. It currently has no effect unless the power manager is in
-    // the dozing state.
-    DRAW_WAKE_LOCK = 128;
-}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index fe65bda3..8de30f8 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -56,13 +56,13 @@
 import "frameworks/base/core/proto/android/service/procstats.proto";
 import "frameworks/base/core/proto/android/service/restricted_image.proto";
 import "frameworks/base/core/proto/android/service/sensor_service.proto";
-import "frameworks/base/core/proto/android/service/usb.proto";
 import "frameworks/base/core/proto/android/util/event_log_tags.proto";
 import "frameworks/base/core/proto/android/util/log.proto";
 import "frameworks/base/core/proto/android/util/textdump.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
 import "frameworks/base/core/proto/android/section.proto";
 import "frameworks/base/proto/src/ipconnectivity.proto";
+import "frameworks/proto_logging/stats/enums/service/usb.proto";
 
 package android.os;
 
diff --git a/core/proto/android/stats/devicepolicy/device_policy.proto b/core/proto/android/server/accessibility.proto
similarity index 70%
rename from core/proto/android/stats/devicepolicy/device_policy.proto
rename to core/proto/android/server/accessibility.proto
index af30cf3..7fe7f0d 100644
--- a/core/proto/android/stats/devicepolicy/device_policy.proto
+++ b/core/proto/android/server/accessibility.proto
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,12 @@
 
 syntax = "proto2";
 
-package android.stats.devicepolicy;
+import "frameworks/base/core/proto/android/typedef.proto";
+
+package com.android.server.accessibility;
+
 option java_multiple_files = true;
 
-message StringList {
-  repeated string string_value = 1;
+/* The proto format trace entry for accessibility service */
+message AccessibilityDumpProto {
 }
diff --git a/core/proto/android/server/accessibilitytrace.proto b/core/proto/android/server/accessibilitytrace.proto
new file mode 100644
index 0000000..1fc4a01
--- /dev/null
+++ b/core/proto/android/server/accessibilitytrace.proto
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/server/accessibility.proto";
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
+
+package com.android.server.accessibility;
+
+option java_multiple_files = true;
+
+/* represents a file full of accessibility trace entries.
+   Encoded, it should start with 0x9 0x41 0x31 0x31 0x59 0x54 0x52 0x41 0x43 (.A11YTRAC), such
+   that they can be easily identified. */
+message AccessibilityTraceFileProto {
+
+    /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+       (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+        constants into .proto files. */
+    enum MagicNumber {
+        INVALID = 0;
+        MAGIC_NUMBER_L = 0x59313141;  /* A11Y (little-endian ASCII) */
+        MAGIC_NUMBER_H = 0x43415254;  /* TRAC (little-endian ASCII) */
+    }
+
+    optional fixed64 magic_number = 1;  /* Must be the first field, set to value in MagicNumber */
+    repeated AccessibilityTraceProto entry = 2;
+}
+
+/* one accessibility trace entry. */
+message AccessibilityTraceProto {
+    /* required: elapsed realtime in nanos since boot of when this entry was logged */
+    optional fixed64 elapsed_realtime_nanos = 1;
+    optional string calendar_time = 2;
+
+    optional string process_name = 3;
+    optional string thread_id_name = 4;
+
+    /* where the trace originated */
+    optional string where = 5;
+
+    optional string calling_pkg = 6;
+    optional string calling_params = 7;
+    optional string calling_stacks = 8;
+
+    optional AccessibilityDumpProto accessibility_service = 9;
+    optional com.android.server.wm.WindowManagerServiceDumpProto window_manager_service = 10;
+}
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 2d2ead4..fa046c6 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -20,7 +20,6 @@
 
 import "frameworks/base/core/proto/android/app/activitymanager.proto";
 import "frameworks/base/core/proto/android/app/appexitinfo.proto";
-import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/app/notification.proto";
 import "frameworks/base/core/proto/android/app/profilerinfo.proto";
 import "frameworks/base/core/proto/android/content/component_name.proto";
@@ -35,6 +34,7 @@
 import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
 import "frameworks/base/core/proto/android/util/common.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/app/enums.proto";
 
 option java_multiple_files = true;
 
diff --git a/core/proto/android/server/bluetooth_manager_service.proto b/core/proto/android/server/bluetooth_manager_service.proto
index 998413f..c33f66a 100644
--- a/core/proto/android/server/bluetooth_manager_service.proto
+++ b/core/proto/android/server/bluetooth_manager_service.proto
@@ -17,8 +17,8 @@
 syntax = "proto2";
 package com.android.server;
 
-import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/bluetooth/enums.proto";
 
 option java_multiple_files = true;
 
diff --git a/core/proto/android/server/connectivity/Android.bp b/core/proto/android/server/connectivity/Android.bp
deleted file mode 100644
index 50c238b..0000000
--- a/core/proto/android/server/connectivity/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library_static {
-    name: "datastallprotosnano",
-    proto: {
-        type: "nano",
-    },
-    srcs: [
-        "data_stall_event.proto",
-    ],
-    sdk_version: "system_current",
-    // this is part of updatable modules(NetworkStack) which targets 29(Q)
-    min_sdk_version: "29",
-}
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
deleted file mode 100644
index 787074b..0000000
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package com.android.server.connectivity;
-option java_multiple_files = true;
-option java_outer_classname = "DataStallEventProto";
-
-enum ProbeResult {
-    UNKNOWN = 0;
-    VALID = 1;
-    INVALID = 2;
-    PORTAL = 3;
-    PARTIAL = 4;
-}
-
-enum ApBand {
-    AP_BAND_UNKNOWN = 0;
-    AP_BAND_2GHZ = 1;
-    AP_BAND_5GHZ = 2;
-    AP_BAND_6GHZ = 3;
-}
-
-// Refer to definition in TelephonyManager.java.
-enum RadioTech {
-  RADIO_TECHNOLOGY_UNKNOWN = 0;
-  RADIO_TECHNOLOGY_GPRS = 1;
-  RADIO_TECHNOLOGY_EDGE = 2;
-  RADIO_TECHNOLOGY_UMTS = 3;
-  RADIO_TECHNOLOGY_IS95A = 4;
-  RADIO_TECHNOLOGY_IS95B = 5;
-  RADIO_TECHNOLOGY_1XRTT = 6;
-  RADIO_TECHNOLOGY_EVDO_0 = 7;
-  RADIO_TECHNOLOGY_EVDO_A = 8;
-  RADIO_TECHNOLOGY_HSDPA = 9;
-  RADIO_TECHNOLOGY_HSUPA = 10;
-  RADIO_TECHNOLOGY_HSPA = 11;
-  RADIO_TECHNOLOGY_EVDO_B = 12;
-  RADIO_TECHNOLOGY_LTE = 13;
-  RADIO_TECHNOLOGY_EHRPD = 14;
-  RADIO_TECHNOLOGY_HSPAP = 15;
-  RADIO_TECHNOLOGY_GSM = 16;
-  RADIO_TECHNOLOGY_TD_SCDMA = 17;
-  RADIO_TECHNOLOGY_IWLAN = 18;
-  RADIO_TECHNOLOGY_LTE_CA = 19;
-  RADIO_TECHNOLOGY_NR = 20;
-}
-
-// Cellular specific information.
-message CellularData {
-    // Indicate the radio technology at the time of data stall suspected.
-    optional RadioTech rat_type = 1;
-    // True if device is in roaming network at the time of data stall suspected.
-    optional bool is_roaming = 2;
-    // Registered network MccMnc when data stall happen
-    optional string network_mccmnc = 3;
-    // Indicate the SIM card carrier.
-    optional string sim_mccmnc = 4;
-    // Signal strength level at the time of data stall suspected.
-    optional int32 signal_strength = 5;
-}
-
-// Wifi specific information.
-message WifiData {
-    // Signal strength at the time of data stall suspected.
-    // RSSI range is between -55 to -110.
-    optional int32 signal_strength = 1;
-    // AP band.
-    optional ApBand wifi_band = 2;
-}
-
-message DnsEvent {
-    // The dns return code.
-    repeated int32 dns_return_code = 1;
-    // Indicate the timestamp of the dns event.
-    repeated int64 dns_time = 2;
-}
diff --git a/core/proto/android/server/enums.proto b/core/proto/android/server/enums.proto
deleted file mode 100644
index 89f7010..0000000
--- a/core/proto/android/server/enums.proto
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.server;
-
-option java_outer_classname = "ServerProtoEnums";
-option java_multiple_files = true;
-
-enum DeviceIdleModeEnum {
-    // Device idle mode - not active.
-    DEVICE_IDLE_MODE_OFF = 0;
-    // Device idle mode - active in lightweight mode.
-    DEVICE_IDLE_MODE_LIGHT = 1;
-    // Device idle mode - active in full mode.
-    DEVICE_IDLE_MODE_DEEP = 2;
-}
-
-enum ErrorSource {
-    ERROR_SOURCE_UNKNOWN = 0;
-    // Data app
-    DATA_APP = 1;
-    // System app
-    SYSTEM_APP = 2;
-    // System server.
-    SYSTEM_SERVER = 3;
-}
diff --git a/core/proto/android/server/job/enums.proto b/core/proto/android/server/job/enums.proto
deleted file mode 100644
index 50fc031..0000000
--- a/core/proto/android/server/job/enums.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package com.android.server.job;
-
-// This file is for JobScheduler enums inside the server directory. If you're
-// adding enums for app-side code, use the file in
-// frameworks/base/core/proto/android/app/job.
-option java_outer_classname = "JobServerProtoEnums";
-option java_multiple_files = true;
-
-// Set of constraints that a job potentially needs satisfied before it can run.
-// Defined in
-// frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java
-enum ConstraintEnum {
-    CONSTRAINT_UNKNOWN = 0;
-    CONSTRAINT_CHARGING = 1;
-    CONSTRAINT_BATTERY_NOT_LOW = 2;
-    CONSTRAINT_STORAGE_NOT_LOW = 3;
-    CONSTRAINT_TIMING_DELAY = 4;
-    CONSTRAINT_DEADLINE = 5;
-    CONSTRAINT_IDLE = 6;
-    CONSTRAINT_CONNECTIVITY = 7;
-    CONSTRAINT_CONTENT_TRIGGER = 8;
-    CONSTRAINT_DEVICE_NOT_DOZING = 9;
-    CONSTRAINT_WITHIN_QUOTA = 10;
-    CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 11;
-}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 0e2bd26..d187220 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -20,7 +20,6 @@
 
 option java_multiple_files = true;
 
-import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/content/clipdata.proto";
 import "frameworks/base/core/proto/android/content/component_name.proto";
 import "frameworks/base/core/proto/android/content/intent.proto";
@@ -29,10 +28,11 @@
 import "frameworks/base/core/proto/android/os/bundle.proto";
 import "frameworks/base/core/proto/android/os/persistablebundle.proto";
 import "frameworks/base/core/proto/android/server/appstatetracker.proto";
-import "frameworks/base/core/proto/android/server/job/enums.proto";
 import "frameworks/base/core/proto/android/server/statlogger.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
 import "frameworks/base/core/proto/android/util/quotatracker.proto";
+import "frameworks/proto_logging/stats/enums/app/job/enums.proto";
+import "frameworks/proto_logging/stats/enums/server/job/enums.proto";
 
 message JobSchedulerServiceDumpProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/server/location/enums.proto b/core/proto/android/server/location/enums.proto
deleted file mode 100644
index 943ff18..0000000
--- a/core/proto/android/server/location/enums.proto
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.server.location;
-
-option java_outer_classname = "ServerLocationProtoEnums";
-option java_multiple_files = true;
-
-// GPS Signal Quality levels,
-// primarily used by location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
-enum GpsSignalQualityEnum {
-    GPS_SIGNAL_QUALITY_UNKNOWN = -1;
-    GPS_SIGNAL_QUALITY_POOR = 0;
-    GPS_SIGNAL_QUALITY_GOOD = 1;
-}
-
-// A type which distinguishes different categories of NI request, such as VOICE, UMTS_SUPL etc.
-enum GnssNiType {
-    VOICE = 1;
-    UMTS_SUPL = 2;
-    UMTS_CTRL_PLANE = 3;
-    EMERGENCY_SUPL = 4;
-};
-
-// GNSS NI responses, used to define the response in NI structures.
-enum GnssUserResponseType {
-    RESPONSE_ACCEPT = 1;
-    RESPONSE_DENY = 2;
-    RESPONSE_NORESP = 3;
-};
-
-// GNSS NI data encoding scheme.
-enum GnssNiEncodingType {
-    ENC_NONE = 0;
-    ENC_SUPL_GSM_DEFAULT = 1;
-    ENC_SUPL_UTF8 = 2;
-    ENC_SUPL_UCS2 = 3;
-    ENC_UNKNOWN = -1;
-};
-
-// Protocol stack that initiated the non-framework location request.
-enum NfwProtocolStack {
-    // Cellular control plane requests.
-    CTRL_PLANE = 0;
-    // All types of SUPL requests.
-    SUPL = 1;
-    // All types of requests from IMS.
-    IMS = 10;
-    // All types of requests from SIM.
-    SIM = 11;
-    // Requests from other protocol stacks.
-    OTHER_PROTOCOL_STACK = 100;
-};
-
-// Source initiating/receiving the location information.
-enum NfwRequestor  {
-    // Wireless service provider.
-    CARRIER = 0;
-    // Device manufacturer.
-    OEM = 10;
-    // Modem chipset vendor.
-    MODEM_CHIPSET_VENDOR = 11;
-    // GNSS chipset vendor.
-    GNSS_CHIPSET_VENDOR = 12;
-    // Other chipset vendor.
-    OTHER_CHIPSET_VENDOR = 13;
-    // Automobile client.
-    AUTOMOBILE_CLIENT = 20;
-    // Other sources.
-    OTHER_REQUESTOR = 100;
-};
-
-// Indicates whether location information was provided for this request.
-enum NfwResponseType {
-    // Request rejected because framework has not given permission for this use case.
-    REJECTED = 0;
-    // Request accepted but could not provide location because of a failure.
-    ACCEPTED_NO_LOCATION_PROVIDED = 1;
-    // Request accepted and location provided.
-    ACCEPTED_LOCATION_PROVIDED = 2;
-};
-
-// The SUPL mode.
-enum SuplMode {
-    // Mobile Station Based.
-    MSB = 0x01;
-    // Mobile Station Assisted.
-    MSA = 0x02;
-};
-
-// Enum that hold the bit masks for various LTE Positioning Profile settings (LPP_PROFILE
-// configuration parameter). If none of the bits in the enum are set, the default setting is
-// Radio Resource Location Protocol(RRLP).
-enum LppProfile {
-    // Enable LTE Positioning Protocol user plane.
-    USER_PLANE = 0x01;
-    // Enable LTE Positioning Protocol Control plane.
-    CONTROL_PLANE = 0x02;
-};
-
-// Positioning protocol on A-Glonass system.
-enum GlonassPosProtocol {
-    // Radio Resource Control(RRC) control-plane.
-    RRC_CPLANE = 0x01;
-    // Radio Resource Location user-plane.
-    RRLP_CPLANE = 0x02;
-    // LTE Positioning Protocol User plane.
-    LPP_UPLANE = 0x04;
-};
-
-// Configurations of how GPS functionalities should be locked when user turns off GPS On setting.
-enum GpsLock {
-    // Lock Mobile Originated GPS functionalitues.
-    MO = 0x01;
-    // Lock Network Initiated GPS functionalities.
-    NI = 0x02;
-};
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index a2f2c46..0d23946 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -19,16 +19,16 @@
 
 option java_multiple_files = true;
 
-import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/content/intent.proto";
-import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/os/looper.proto";
 import "frameworks/base/core/proto/android/os/powermanager.proto";
 import "frameworks/base/core/proto/android/os/worksource.proto";
 import "frameworks/base/core/proto/android/providers/settings.proto";
 import "frameworks/base/core/proto/android/server/wirelesschargerdetector.proto";
-import "frameworks/base/core/proto/android/view/enums.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/app/enums.proto";
+import "frameworks/proto_logging/stats/enums/os/enums.proto";
+import "frameworks/proto_logging/stats/enums/view/enums.proto";
 
 message PowerManagerServiceDumpProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 0453d3f3..c4c007d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -24,7 +24,6 @@
 import "frameworks/base/core/proto/android/server/surfaceanimator.proto";
 import "frameworks/base/core/proto/android/view/displaycutout.proto";
 import "frameworks/base/core/proto/android/view/displayinfo.proto";
-import "frameworks/base/core/proto/android/view/enums.proto";
 import "frameworks/base/core/proto/android/view/surface.proto";
 import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
@@ -34,6 +33,8 @@
 import "frameworks/base/core/proto/android/view/insetssource.proto";
 import "frameworks/base/core/proto/android/view/insetssourcecontrol.proto";
 
+import "frameworks/proto_logging/stats/enums/view/enums.proto";
+
 package com.android.server.wm;
 
 option java_multiple_files = true;
@@ -206,9 +207,10 @@
     optional WindowStateProto input_method_control_target = 29;
     optional WindowStateProto current_focus = 30;
     optional ImeInsetsSourceProviderProto ime_insets_source_provider = 31;
-    optional bool can_show_ime = 32;
+    optional bool can_show_ime = 32 [deprecated=true];
 
     optional DisplayRotationProto display_rotation = 33;
+    optional int32 ime_policy = 34;
 }
 
 /* represents DisplayArea object */
diff --git a/core/proto/android/service/battery.proto b/core/proto/android/service/battery.proto
index 586411f..3a112e7 100644
--- a/core/proto/android/service/battery.proto
+++ b/core/proto/android/service/battery.proto
@@ -20,8 +20,8 @@
 option java_multiple_files = true;
 option java_outer_classname = "BatteryServiceProto";
 
-import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/os/enums.proto";
 
 message BatteryServiceDumpProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index 7a4c070..57051f0 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -21,8 +21,8 @@
 option java_outer_classname = "ProcessStatsServiceProto";
 
 import "frameworks/base/core/proto/android/util/common.proto";
-import "frameworks/base/core/proto/android/service/procstats_enum.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/service/procstats_enum.proto";
 
 /**
  * Data from ProcStatsService Dumpsys
diff --git a/core/proto/android/service/procstats_enum.proto b/core/proto/android/service/procstats_enum.proto
deleted file mode 100644
index 2abf373..0000000
--- a/core/proto/android/service/procstats_enum.proto
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.service.procstats;
-
-option java_multiple_files = true;
-option java_outer_classname = "ProcessStatsEnums";
-
-enum ScreenState {
-    SCREEN_STATE_UNKNOWN = 0;
-    SCREEN_STATE_OFF = 1;
-    SCREEN_STATE_ON = 2;
-}
-
-enum MemoryState {
-    MEMORY_STATE_UNKNOWN = 0;
-    MEMORY_STATE_NORMAL = 1;     // normal.
-    MEMORY_STATE_MODERATE = 2;   // moderate memory pressure.
-    MEMORY_STATE_LOW = 3;        // low memory.
-    MEMORY_STATE_CRITICAL = 4;   // critical memory.
-}
-
-// this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
-// and not frameworks/base/core/java/android/app/ActivityManager.java
-enum ProcessState {
-    PROCESS_STATE_UNKNOWN = 0;
-    // Persistent system process.
-    PROCESS_STATE_PERSISTENT = 1;
-    // Top activity; actually any visible activity.
-    PROCESS_STATE_TOP = 2;
-    // Important foreground process (ime, wallpaper, etc).
-    PROCESS_STATE_IMPORTANT_FOREGROUND = 3;
-    // Important background process.
-    PROCESS_STATE_IMPORTANT_BACKGROUND = 4;
-    // Performing backup operation.
-    PROCESS_STATE_BACKUP = 5;
-    // Background process running a service.
-    PROCESS_STATE_SERVICE = 6;
-    // Process not running, but would be if there was enough RAM.
-    PROCESS_STATE_SERVICE_RESTARTING = 7;
-    // Process running a receiver.
-    PROCESS_STATE_RECEIVER = 8;
-    // Heavy-weight process (currently not used).
-    PROCESS_STATE_HEAVY_WEIGHT = 9;
-    // Process hosting home/launcher app when not on top.
-    PROCESS_STATE_HOME = 10;
-    // Process hosting the last app the user was in.
-    PROCESS_STATE_LAST_ACTIVITY = 11;
-    // Cached process hosting a previous activity.
-    PROCESS_STATE_CACHED_ACTIVITY = 12;
-    // Cached process hosting a client activity.
-    PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 13;
-    // Cached process that is empty.
-    PROCESS_STATE_CACHED_EMPTY = 14;
-}
-
-enum ServiceOperationState {
-    SERVICE_OPERATION_STATE_UNKNOWN = 0;
-    SERVICE_OPERATION_STATE_RUNNING = 1;
-    SERVICE_OPERATION_STATE_STARTED = 2;
-    SERVICE_OPERATION_STATE_FOREGROUND = 3;
-    SERVICE_OPERATION_STATE_BOUND = 4;
-    SERVICE_OPERATION_STATE_EXECUTING = 5;
-}
-
-// this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
-// and not frameworks/base/core/java/android/app/ActivityManager.java
-enum AggregatedProcessState {
-    AGGREGATED_PROCESS_STATE_UNKNOWN = 0;
-    // Persistent system process; PERSISTENT or PERSISTENT_UI in ActivityManager
-    AGGREGATED_PROCESS_STATE_PERSISTENT = 1;
-    // Top activity; actually any visible activity; TOP or TOP_SLEEPING in ActivityManager
-    AGGREGATED_PROCESS_STATE_TOP = 2;
-    // Bound top foreground process; BOUND_TOP or BOUND_FOREGROUND_SERVICE in ActivityManager
-    AGGREGATED_PROCESS_STATE_BOUND_TOP_OR_FGS = 3;
-    // Important foreground process; FOREGROUND_SERVICE in ActivityManager
-    AGGREGATED_PROCESS_STATE_FGS = 4;
-    // Important foreground process ; IMPORTANT_FOREGROUND in ActivityManager
-    AGGREGATED_PROCESS_STATE_IMPORTANT_FOREGROUND = 5;
-    // Various background processes; IMPORTANT_BACKGROUND, TRANSIENT_BACKGROUND, BACKUP, SERVICE,
-    // HEAVY_WEIGHT in ActivityManager
-    AGGREGATED_PROCESS_STATE_BACKGROUND = 6;
-    // Process running a receiver; RECEIVER in ActivityManager
-    AGGREGATED_PROCESS_STATE_RECEIVER = 7;
-    // Various cached processes; HOME, LAST_ACTIVITY, CACHED_ACTIVITY, CACHED_RECENT,
-    // CACHED_ACTIVITY_CLIENT, CACHED_EMPTY in ActivityManager
-    AGGREGATED_PROCESS_STATE_CACHED = 8;
-}
\ No newline at end of file
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
deleted file mode 100644
index 40c5a85..0000000
--- a/core/proto/android/service/usb.proto
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.service.usb;
-
-option java_multiple_files = true;
-option java_outer_classname = "UsbServiceProto";
-
-import "frameworks/base/core/proto/android/content/component_name.proto";
-import "frameworks/base/core/proto/android/service/enums.proto";
-import "frameworks/base/core/proto/android/privacy.proto";
-
-message UsbServiceDumpProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbDeviceManagerProto device_manager = 1;
-    optional UsbHostManagerProto host_manager = 2;
-    optional UsbPortManagerProto port_manager = 3;
-    optional UsbAlsaManagerProto alsa_manager = 4;
-    optional UsbSettingsManagerProto settings_manager = 5;
-    optional UsbPermissionsManagerProto permissions_manager = 6;
-}
-
-message UsbDeviceManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbHandlerProto handler = 1;
-    optional UsbDebuggingManagerProto debugging_manager = 2;
-}
-
-message UsbHandlerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    /* Same as android.hardware.usb.gadget.V1_0.GadgetFunction.* */
-    enum Function {
-        FUNCTION_ADB = 1;
-        FUNCTION_ACCESSORY = 2;
-        FUNCTION_MTP = 4;
-        FUNCTION_MIDI = 8;
-        FUNCTION_PTP = 16;
-        FUNCTION_RNDIS = 32;
-        FUNCTION_AUDIO_SOURCE = 64;
-    }
-
-    repeated Function current_functions = 1;
-    optional bool current_functions_applied = 2;
-    repeated Function screen_unlocked_functions = 3;
-    optional bool screen_locked = 4;
-    optional bool connected = 5;
-    optional bool configured = 6;
-    optional UsbAccessoryProto current_accessory = 7;
-    optional bool host_connected = 8;
-    optional bool source_power = 9;
-    optional bool sink_power = 10;
-    optional bool usb_charging = 11;
-    optional bool hide_usb_notification = 12;
-    optional bool audio_accessory_connected = 13;
-    optional bool adb_enabled = 14;
-    optional string kernel_state = 15;
-    optional string kernel_function_list = 16;
-}
-
-message UsbAccessoryProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional string manufacturer = 1;
-    optional string model = 2;
-    // For "classical" USB-accessories the manufacturer bakes this into the
-    // firmware of the device. If an Android phone is configured as accessory, the
-    // app that sets up the accessory side of the connection set this. Either way,
-    // these are part of the detection protocol, and so they cannot be user set or
-    // unique.
-    optional string description = 3;
-    optional string version = 4;
-    optional string uri = 5 [ (android.privacy).dest = DEST_EXPLICIT ];
-    // Non-resettable hardware ID.
-    optional string serial = 6 [ (android.privacy).dest = DEST_LOCAL ];
-}
-
-message UsbDebuggingManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional bool connected_to_adb = 1;
-    // A workstation that connects to the phone for debugging is identified by
-    // this key.
-    optional string last_key_received = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
-    optional string user_keys = 3 [ (android.privacy).dest = DEST_LOCAL ];
-    optional string system_keys = 4 [ (android.privacy).dest = DEST_LOCAL ];
-}
-
-message UsbHostManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional android.content.ComponentNameProto default_usb_host_connection_handler = 1;
-    repeated UsbDeviceProto devices = 2;
-    optional int32 num_connects = 3;
-    repeated UsbConnectionRecordProto connections = 4;
-}
-
-message UsbDeviceProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // Generic USB name, not user-provided.
-    optional string name = 1;
-    // ID specific to the vendor, not the device.
-    optional int32 vendor_id = 2;
-    // ID of this product type: Each vendor gives each product a unique ID. E.g.
-    // all mice of the same model would have the same ID.
-    optional int32 product_id = 3;
-    optional int32 class = 4;
-    optional int32 subclass = 5;
-    optional int32 protocol = 6;
-    optional string manufacturer_name = 7;
-    optional string product_name = 8;
-    optional string version = 9;
-    // Non-resettable hardware ID.
-    optional string serial_number = 10 [ (android.privacy).dest = DEST_LOCAL ];
-    repeated UsbConfigurationProto configurations = 11;
-}
-
-message UsbConfigurationProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // A single USB device can have several configurations and the app accessing
-    // the USB device can switch between them. At any time only one can be active.
-    // Each configuration can present completely different interfaces end
-    // endpoints, i.e. a completely different behavior.
-    optional int32 id = 1;
-    // Hardware-defined name, not set by the user.
-    optional string name = 2;
-    optional uint32 attributes = 3;
-    optional int32 max_power = 4;
-    repeated UsbInterfaceProto interfaces = 5;
-}
-
-message UsbInterfaceProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // Hardware defined. This is the id used by the app to identify the interface.
-    optional int32 id = 1;
-    optional int32 alternate_settings = 2;
-    optional string name = 3;
-    optional int32 class = 4;
-    optional int32 subclass = 5;
-    optional int32 protocol = 6;
-    repeated UsbEndPointProto endpoints = 7;
-}
-
-message UsbEndPointProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 endpoint_number = 1;
-    optional android.service.UsbEndPointDirection direction = 2;
-      // The address of the endpoint. Needed to read and write to the endpoint.
-    optional int32 address = 3;
-    optional android.service.UsbEndPointType type = 4;
-    optional uint32 attributes = 5;
-    optional int32 max_packet_size = 6;
-    optional int32 interval = 7;
-}
-
-message UsbConnectionRecordProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // usb device's address, e.g. 001/002, nothing about the phone
-    optional string device_address = 1;
-    optional android.service.UsbConnectionRecordMode mode = 2;
-    optional int64 timestamp = 3;
-    optional int32 manufacturer = 4;
-    optional int32 product = 5;
-    optional UsbIsHeadsetProto is_headset = 6;
-}
-
-message UsbIsHeadsetProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional bool in = 1;
-    optional bool out = 2;
-}
-
-message UsbPortManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional bool is_simulation_active = 1;
-    repeated UsbPortInfoProto usb_ports = 2;
-}
-
-message UsbPortInfoProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbPortProto port = 1;
-    optional UsbPortStatusProto status = 2;
-    optional bool can_change_mode = 3;
-    optional bool can_change_power_role = 4;
-    optional bool can_change_data_role = 5;
-    optional int64 connected_at_millis = 6;
-    optional int64 last_connect_duration_millis = 7;
-}
-
-message UsbPortProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    /* Same as android.hardware.usb.V1_1.Constants.PortMode_1_1 */
-    enum Mode {
-        MODE_NONE = 0;
-        MODE_UFP = 1;
-        MODE_DFP = 2;
-        MODE_DRP = 3;
-        MODE_AUDIO_ACCESSORY = 4;
-        MODE_DEBUG_ACCESSORY = 8;
-    }
-
-    // ID of the port. A device (eg: Chromebooks) might have multiple ports.
-    optional string id = 1;
-    repeated Mode supported_modes = 2;
-}
-
-/* Same as android.hardware.usb.V1_2.Constants.ContaminantPresenceStatus */
-enum ContaminantPresenceStatus {
-    CONTAMINANT_STATUS_UNKNOWN = 0;
-    CONTAMINANT_STATUS_NOT_SUPPORTED = 1;
-    CONTAMINANT_STATUS_DISABLED = 2;
-    CONTAMINANT_STATUS_NOT_DETECTED = 3;
-    CONTAMINANT_STATUS_DETECTED = 4;
-}
-
-message UsbPortStatusProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    /* Same as android.hardware.usb.V1_0.Constants.PortPowerRole */
-    enum PowerRole {
-        POWER_ROLE_NONE = 0;
-        POWER_ROLE_SOURCE = 1;
-        POWER_ROLE_SINK = 2;
-    }
-
-    /* Same as android.hardware.usb.V1_0.Constants.PortDataRole */
-    enum DataRole {
-        DATA_ROLE_NONE = 0;
-        DATA_ROLE_HOST = 1;
-        DATA_ROLE_DEVICE = 2;
-    }
-
-    optional bool connected = 1;
-    optional UsbPortProto.Mode current_mode = 2;
-    optional PowerRole power_role = 3;
-    optional DataRole data_role = 4;
-    repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
-    optional ContaminantPresenceStatus contaminant_presence_status = 6;
-}
-
-message UsbPortStatusRoleCombinationProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbPortStatusProto.PowerRole power_role = 1;
-    optional UsbPortStatusProto.DataRole data_role = 2;
-}
-
-message UsbAlsaManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 cards_parser = 1;
-    repeated UsbAlsaDeviceProto alsa_devices = 2;
-    repeated UsbMidiDeviceProto midi_devices = 3;
-}
-
-message UsbAlsaDeviceProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 card = 1;
-    optional int32 device = 2;
-    optional string name = 3;
-    optional bool has_playback = 4;
-    optional bool has_capture = 5;
-    // usb device's address, e.g. 001/002, nothing about the phone
-    optional string address = 6;
-}
-
-message UsbMidiDeviceProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 card = 1;
-    optional int32 device = 2;
-    // usb device's address, e.g. 001/002, nothing about the phone
-    optional string device_address = 3;
-}
-
-message UsbSettingsManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    repeated UsbUserSettingsManagerProto user_settings = 1;
-    repeated UsbProfileGroupSettingsManagerProto profile_group_settings = 2;
-}
-
-message UsbUserSettingsManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 user_id = 1;
-    reserved 2; // previously device_permissions, now unused
-    reserved 3; // previously accessory_permissions, now unused
-    repeated UsbDeviceAttachedActivities device_attached_activities = 4;
-    repeated UsbAccessoryAttachedActivities accessory_attached_activities = 5;
-}
-
-message UsbProfileGroupSettingsManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // The user id of the personal profile if the device has a work profile.
-    optional int32 parent_user_id = 1;
-    repeated UsbSettingsDevicePreferenceProto device_preferences = 2;
-    repeated UsbSettingsAccessoryPreferenceProto accessory_preferences = 3;
-}
-
-message UsbSettingsDevicePreferenceProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbDeviceFilterProto filter = 1;
-    optional UserPackageProto user_package = 2;
-}
-
-message UsbPermissionsManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    repeated UsbUserPermissionsManagerProto user_permissions = 1;
-}
-
-message UsbUserPermissionsManagerProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 user_id = 1;
-
-    repeated UsbDevicePermissionProto device_permissions = 2;
-    repeated UsbAccessoryPermissionProto accessory_permissions = 3;
-
-    repeated UsbDevicePersistentPermissionProto device_persistent_permissions = 4;
-    repeated UsbAccessoryPersistentPermissionProto accessory_persistent_permissions = 5;
-}
-
-message UsbDevicePermissionProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // Name of device set by manufacturer
-    // All devices of the same model have the same name
-    optional string device_name = 1;
-    repeated int32 uids = 2;
-}
-
-message UsbAccessoryPermissionProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // Description of accessory set by manufacturer
-    // All accessories of the same model have the same description
-    optional string accessory_description = 1;
-    repeated int32 uids = 2;
-}
-
-message UsbDevicePersistentPermissionProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbDeviceFilterProto device_filter = 1;
-    repeated UsbUidPermissionProto permission_values = 2;
-}
-
-message UsbAccessoryPersistentPermissionProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbAccessoryFilterProto accessory_filter = 1;
-    repeated UsbUidPermissionProto permission_values = 2;
-}
-
-message UsbUidPermissionProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 uid = 1;
-    optional bool is_granted = 2;
-}
-
-message UsbDeviceFilterProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // Mirrors the vendor_id of UsbDeviceProto.
-    optional int32 vendor_id = 1;
-    optional int32 product_id = 2;
-    optional int32 class = 3;
-    optional int32 subclass = 4;
-    optional int32 protocol = 5;
-    optional string manufacturer_name = 6;
-    optional string product_name = 7;
-    optional string serial_number = 8 [ (android.privacy).dest = DEST_EXPLICIT ];
-}
-
-message UserPackageProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional int32 user_id = 1;
-    optional string package_name =2;
-}
-
-message UsbSettingsAccessoryPreferenceProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional UsbAccessoryFilterProto filter = 1;
-    optional UserPackageProto user_package = 2;
-}
-
-message UsbAccessoryFilterProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional string manufacturer = 1;
-    optional string model = 2;
-    optional string version = 3;
-}
-
-message UsbDeviceAttachedActivities {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional android.content.ComponentNameProto activity = 1;
-    repeated UsbDeviceFilterProto filters = 2;
-}
-
-message UsbAccessoryAttachedActivities {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional android.content.ComponentNameProto activity = 1;
-    repeated UsbAccessoryFilterProto filters = 2;
-}
diff --git a/core/proto/android/stats/camera/Android.bp b/core/proto/android/stats/camera/Android.bp
deleted file mode 100644
index cc75e57..0000000
--- a/core/proto/android/stats/camera/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library {
-    name: "cameraprotosnano",
-    proto: {
-        type: "nano",
-    },
-    srcs: [
-        "*.proto",
-    ],
-    java_version: "1.8",
-    target: {
-        android: {
-            jarjar_rules: "jarjar-rules.txt",
-        },
-        host: {
-            static_libs: ["libprotobuf-java-nano"],
-        }
-    },
-    sdk_version: "core_platform",
-}
diff --git a/core/proto/android/stats/camera/camera.proto b/core/proto/android/stats/camera/camera.proto
deleted file mode 100644
index 4062855..0000000
--- a/core/proto/android/stats/camera/camera.proto
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.stats.camera;
-option java_multiple_files = true;
-
-message CameraStreamProto {
-    // The stream width (in pixels)
-    optional int32 width = 1;
-    // The stream height (in pixels)
-    optional int32 height = 2;
-    // The format of the stream
-    optional int32 format = 3;
-    // The dataspace of the stream
-    optional int32 data_space = 4;
-    // The usage flag of the stream
-    optional int64 usage = 5;
-
-    // The number of requests for this stream
-    optional int64 request_count = 6;
-    // The number of buffer error for this stream
-    optional int64 error_count = 7;
-    // The capture latency of first request for this stream
-    optional int32 first_capture_latency_millis = 8;
-
-    // The maximum number of hal buffers
-    optional int32 max_hal_buffers = 9;
-    // The maximum number of app buffers
-    optional int32 max_app_buffers = 10;
-}
diff --git a/core/proto/android/stats/camera/jarjar-rules.txt b/core/proto/android/stats/camera/jarjar-rules.txt
deleted file mode 100644
index 40043a86..0000000
--- a/core/proto/android/stats/camera/jarjar-rules.txt
+++ /dev/null
@@ -1 +0,0 @@
-rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
diff --git a/core/proto/android/stats/connectivity/Android.bp b/core/proto/android/stats/connectivity/Android.bp
deleted file mode 100644
index 5e6ac3c..0000000
--- a/core/proto/android/stats/connectivity/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library_static {
-    name: "networkstackprotos",
-    proto: {
-        type: "lite",
-    },
-    srcs: [
-        "network_stack.proto",
-    ],
-    sdk_version: "system_29",
-}
-
-java_library_static {
-    name: "tetheringprotos",
-    proto: {
-        type: "lite",
-    },
-    srcs: [
-        "tethering.proto",
-    ],
-    apex_available: [
-        "com.android.tethering",
-    ],
-    sdk_version: "system_current",
-}
diff --git a/core/proto/android/stats/connectivity/network_stack.proto b/core/proto/android/stats/connectivity/network_stack.proto
deleted file mode 100644
index e9726d7..0000000
--- a/core/proto/android/stats/connectivity/network_stack.proto
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.connectivity;
-option java_multiple_files = true;
-option java_outer_classname = "NetworkStackProto";
-
-enum DhcpRenewResult {
-    RR_UNKNOWN = 0;
-    RR_SUCCESS = 1;
-    RR_ERROR_NAK = 2;
-    RR_ERROR_IP_MISMATCH = 3;
-    RR_ERROR_IP_EXPIRE = 4;
-}
-
-enum DisconnectCode {
-    DC_NONE = 0;
-    DC_NORMAL_TERMINATION = 1;
-    DC_PROVISIONING_FAIL = 2;
-    DC_ERROR_STARTING_IPV4 = 4;
-    DC_ERROR_STARTING_IPV6 = 5;
-    DC_ERROR_STARTING_IPREACHABILITYMONITOR = 6;
-    DC_INVALID_PROVISIONING = 7;
-    DC_INTERFACE_NOT_FOUND = 8;
-    DC_PROVISIONING_TIMEOUT = 9;
-}
-
-enum TransportType {
-    TT_UNKNOWN = 0;
-    // Indicates this network uses a Cellular transport
-    TT_CELLULAR = 1;
-    // Indicates this network uses a Wi-Fi transport
-    TT_WIFI = 2;
-    // Indicates this network uses a Bluetooth transport
-    TT_BLUETOOTH = 3;
-    // Indicates this network uses an Ethernet transport
-    TT_ETHERNET = 4;
-    // Indicates this network uses a Wi-Fi Aware transport
-    TT_WIFI_AWARE = 5;
-    // Indicates this network uses a LoWPAN transport
-    TT_LOWPAN = 6;
-    // Indicates this network uses a Cellular+VPN transport
-    TT_CELLULAR_VPN = 7;
-    // Indicates this network uses a Wi-Fi+VPN transport
-    TT_WIFI_VPN = 8;
-    // Indicates this network uses a Bluetooth+VPN transport
-    TT_BLUETOOTH_VPN = 9;
-    // Indicates this network uses an Ethernet+VPN transport
-    TT_ETHERNET_VPN = 10;
-    // Indicates this network uses a Wi-Fi+Cellular+VPN transport
-    TT_WIFI_CELLULAR_VPN = 11;
-    // Indicates this network uses for test only
-    TT_TEST = 12;
-}
-
-enum DhcpFeature {
-    DF_UNKNOWN = 0;
-    // DHCP INIT-REBOOT state
-    DF_INITREBOOT = 1;
-    // DHCP rapid commit option
-    DF_RAPIDCOMMIT  = 2;
-    // Duplicate address detection
-    DF_DAD = 3;
-    // Fast initial Link setup
-    DF_FILS = 4;
-}
-
-enum HostnameTransResult {
-    HTR_UNKNOWN = 0;
-    HTR_SUCCESS = 1;
-    HTR_FAILURE = 2;
-    HTR_DISABLE = 3;
-}
-
-enum ProbeResult {
-    PR_UNKNOWN = 0;
-    PR_SUCCESS = 1;
-    PR_FAILURE = 2;
-    PR_PORTAL = 3;
-    // DNS query for the probe host returned a private IP address
-    PR_PRIVATE_IP_DNS = 4;
-}
-
-enum ValidationResult {
-    VR_UNKNOWN = 0;
-    VR_SUCCESS = 1;
-    VR_FAILURE = 2;
-    VR_PORTAL = 3;
-    VR_PARTIAL = 4;
-}
-
-enum ProbeType {
-    PT_UNKNOWN = 0;
-    PT_DNS       = 1;
-    PT_HTTP      = 2;
-    PT_HTTPS     = 3;
-    PT_PAC       = 4;
-    PT_FALLBACK  = 5;
-    PT_PRIVDNS   = 6;
-    PT_CAPPORT_API = 7;
-}
-
-// The Dhcp error code is defined in android.net.metrics.DhcpErrorEvent
-enum DhcpErrorCode {
-    ET_UNKNOWN = 0;
-    ET_L2_ERROR = 1;
-    ET_L3_ERROR = 2;
-    ET_L4_ERROR = 3;
-    ET_DHCP_ERROR = 4;
-    ET_MISC_ERROR = 5;
-    /* Reserve for error type
-    // ET_L2_ERROR_TYPE = ET_L2_ERROR << 8;
-    ET_L2_ERROR_TYPE = 256;
-    // ET_L3_ERROR_TYPE = ET_L3_ERROR << 8;
-    ET_L3_ERROR_TYPE = 512;
-    // ET_L4_ERROR_TYPE = ET_L4_ERROR << 8;
-    ET_L4_ERROR_TYPE = 768;
-    // ET_DHCP_ERROR_TYPE = ET_DHCP_ERROR << 8;
-    ET_DHCP_ERROR_TYPE = 1024;
-    // ET_MISC_ERROR_TYPE = ET_MISC_ERROR << 8;
-    ET_MISC_ERROR_TYPE = 1280;
-    */
-    // ET_L2_TOO_SHORT = (ET_L2_ERROR_TYPE | 0x1) << 16;
-    ET_L2_TOO_SHORT = 16842752;
-    // ET_L2_WRONG_ETH_TYPE = (ET_L2_ERROR_TYPE | 0x2) << 16;
-    ET_L2_WRONG_ETH_TYPE = 16908288;
-    // ET_L3_TOO_SHORT = (ET_L3_ERROR_TYPE | 0x1) << 16;
-    ET_L3_TOO_SHORT = 33619968;
-    // ET_L3_NOT_IPV4 = (ET_L3_ERROR_TYPE | 0x2) << 16;
-    ET_L3_NOT_IPV4 = 33685504;
-    // ET_L3_INVALID_IP = (ET_L3_ERROR_TYPE | 0x3) << 16;
-    ET_L3_INVALID_IP = 33751040;
-    // ET_L4_NOT_UDP = (ET_L4_ERROR_TYPE | 0x1) << 16;
-    ET_L4_NOT_UDP = 50397184;
-    // ET_L4_WRONG_PORT = (ET_L4_ERROR_TYPE | 0x2) << 16;
-    ET_L4_WRONG_PORT = 50462720;
-    // ET_BOOTP_TOO_SHORT = (ET_DHCP_ERROR_TYPE | 0x1) << 16;
-    ET_BOOTP_TOO_SHORT = 67174400;
-    // ET_DHCP_BAD_MAGIC_COOKIE = (ET_DHCP_ERROR_TYPE | 0x2) << 16;
-    ET_DHCP_BAD_MAGIC_COOKIE = 67239936;
-    // ET_DHCP_INVALID_OPTION_LENGTH = (ET_DHCP_ERROR_TYPE | 0x3) << 16;
-    ET_DHCP_INVALID_OPTION_LENGTH = 67305472;
-    // ET_DHCP_NO_MSG_TYPE = (ET_DHCP_ERROR_TYPE | 0x4) << 16;
-    ET_DHCP_NO_MSG_TYPE = 67371008;
-    // ET_DHCP_UNKNOWN_MSG_TYPE = (ET_DHCP_ERROR_TYPE | 0x5) << 16;
-    ET_DHCP_UNKNOWN_MSG_TYPE = 67436544;
-    // ET_DHCP_NO_COOKIE = (ET_DHCP_ERROR_TYPE | 0x6) << 16;
-    ET_DHCP_NO_COOKIE = 67502080;
-    // ET_BUFFER_UNDERFLOW = (ET_MISC_ERROR_TYPE | 0x1) << 16;
-    ET_BUFFER_UNDERFLOW = 83951616;
-    // ET_RECEIVE_ERROR = (ET_MISC_ERROR_TYPE | 0x2) << 16;
-    ET_RECEIVE_ERROR = 84017152;
-    // ET_PARSING_ERROR = (ET_MISC_ERROR_TYPE | 0x3) << 16;
-    ET_PARSING_ERROR = 84082688;
-}
-
-enum NetworkQuirkEvent {
-    QE_UNKNOWN = 0;
-    QE_IPV6_PROVISIONING_ROUTER_LOST = 1;
-}
-
-message NetworkStackEventData {
-
-}
-
diff --git a/core/proto/android/stats/connectivity/tethering.proto b/core/proto/android/stats/connectivity/tethering.proto
deleted file mode 100644
index 13f0b8c..0000000
--- a/core/proto/android/stats/connectivity/tethering.proto
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-syntax = "proto2";
-package android.stats.connectivity;
-option java_multiple_files = true;
-option java_outer_classname = "TetheringProto";
-
-enum ErrorCode {
-    EC_NO_ERROR = 0;
-    EC_UNKNOWN_IFACE = 1;
-    EC_SERVICE_UNAVAIL = 2;
-    EC_UNSUPPORTED = 3;
-    EC_UNAVAIL_IFACE = 4;
-    EC_INTERNAL_ERROR = 5;
-    EC_TETHER_IFACE_ERROR = 6;
-    EC_UNTETHER_IFACE_ERROR = 7;
-    EC_ENABLE_FORWARDING_ERROR = 8;
-    EC_DISABLE_FORWARDING_ERROR = 9;
-    EC_IFACE_CFG_ERROR = 10;
-    EC_PROVISIONING_FAILED = 11;
-    EC_DHCPSERVER_ERROR = 12;
-    EC_ENTITLEMENT_UNKNOWN = 13;
-    EC_NO_CHANGE_TETHERING_PERMISSION = 14;
-    EC_NO_ACCESS_TETHERING_PERMISSION = 15;
-    EC_UNKNOWN_TYPE = 16;
-}
-
-enum DownstreamType {
-    // Unspecific tethering type.
-    DS_UNSPECIFIED = 0;
-    // Wifi tethering type.
-    DS_TETHERING_WIFI = 1;
-    // USB tethering type.
-    DS_TETHERING_USB = 2;
-    // Bluetooth tethering type.
-    DS_TETHERING_BLUETOOTH = 3;
-    // Wifi P2p tethering type.
-    DS_TETHERING_WIFI_P2P = 4;
-    // NCM (Network Control Model) local tethering type.
-    DS_TETHERING_NCM = 5;
-    // Ethernet tethering type.
-    DS_TETHERING_ETHERNET = 6;
-}
-
-enum UpstreamType {
-    UT_UNKNOWN = 0;
-    // Indicates upstream using a Cellular transport.
-    UT_CELLULAR = 1;
-    // Indicates upstream using a Wi-Fi transport.
-    UT_WIFI = 2;
-    // Indicates upstream using a Bluetooth transport.
-    UT_BLUETOOTH = 3;
-    // Indicates upstream using an Ethernet transport.
-    UT_ETHERNET = 4;
-    // Indicates upstream using a Wi-Fi Aware transport.
-    UT_WIFI_AWARE = 5;
-    // Indicates upstream using a LoWPAN transport.
-    UT_LOWPAN = 6;
-    // Indicates upstream using a Cellular+VPN transport.
-    UT_CELLULAR_VPN = 7;
-    // Indicates upstream using a Wi-Fi+VPN transport.
-    UT_WIFI_VPN = 8;
-    // Indicates upstream using a Bluetooth+VPN transport.
-    UT_BLUETOOTH_VPN = 9;
-    // Indicates upstream using an Ethernet+VPN transport.
-    UT_ETHERNET_VPN = 10;
-    // Indicates upstream using a Wi-Fi+Cellular+VPN transport.
-    UT_WIFI_CELLULAR_VPN = 11;
-    // Indicates upstream using for test only.
-    UT_TEST = 12;
-    // Indicates upstream using DUN capability + Cellular transport.
-    UT_DUN_CELLULAR = 13;
-}
-
-enum UserType {
-    // Unknown.
-    USER_UNKNOWN = 0;
-    // Settings.
-    USER_SETTINGS = 1;
-    // System UI.
-    USER_SYSTEMUI = 2;
-    // Google mobile service.
-    USER_GMS = 3;
-}
diff --git a/core/proto/android/stats/devicepolicy/Android.bp b/core/proto/android/stats/devicepolicy/Android.bp
deleted file mode 100644
index 5fb278a..0000000
--- a/core/proto/android/stats/devicepolicy/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library_static {
-    name: "devicepolicyprotosnano",
-    proto: {
-        type: "nano",
-    },
-    srcs: [
-        "*.proto",
-    ],
-    java_version: "1.8",
-    target: {
-        android: {
-            jarjar_rules: "jarjar-rules.txt",
-        },
-        host: {
-            static_libs: ["libprotobuf-java-nano"],
-        }
-    },
-    sdk_version: "core_platform",
-}
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
deleted file mode 100644
index 7c1a049..0000000
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.devicepolicy;
-option java_multiple_files = true;
-
-/**
- * Id for device policy features.
- */
-enum EventId {
-  SET_PASSWORD_QUALITY = 1;
-  SET_PASSWORD_MINIMUM_LENGTH = 2;
-  SET_PASSWORD_MINIMUM_NUMERIC = 3;
-  SET_PASSWORD_MINIMUM_NON_LETTER = 4;
-  SET_PASSWORD_MINIMUM_LETTERS = 5;
-  SET_PASSWORD_MINIMUM_LOWER_CASE = 6;
-  SET_PASSWORD_MINIMUM_UPPER_CASE = 7;
-  SET_PASSWORD_MINIMUM_SYMBOLS = 8;
-  SET_KEYGUARD_DISABLED_FEATURES = 9;
-  LOCK_NOW = 10;
-  WIPE_DATA_WITH_REASON = 11;
-  ADD_USER_RESTRICTION = 12;
-  REMOVE_USER_RESTRICTION = 13;
-  SET_SECURE_SETTING = 14;
-  SET_SECURITY_LOGGING_ENABLED = 15;
-  RETRIEVE_SECURITY_LOGS = 16;
-  RETRIEVE_PRE_REBOOT_SECURITY_LOGS = 17;
-  SET_PERMISSION_POLICY = 18;
-  SET_PERMISSION_GRANT_STATE = 19;
-  INSTALL_KEY_PAIR = 20;
-  INSTALL_CA_CERT = 21;
-  CHOOSE_PRIVATE_KEY_ALIAS = 22;
-  REMOVE_KEY_PAIR = 23;
-  UNINSTALL_CA_CERTS = 24;
-  SET_CERT_INSTALLER_PACKAGE = 25;
-  SET_ALWAYS_ON_VPN_PACKAGE = 26;
-  SET_PERMITTED_INPUT_METHODS = 27;
-  SET_PERMITTED_ACCESSIBILITY_SERVICES = 28;
-  SET_SCREEN_CAPTURE_DISABLED = 29;
-  SET_CAMERA_DISABLED = 30;
-  QUERY_SUMMARY_FOR_USER = 31;
-  QUERY_SUMMARY = 32;
-  QUERY_DETAILS = 33;
-  REBOOT = 34;
-  SET_MASTER_VOLUME_MUTED = 35;
-  SET_AUTO_TIME_REQUIRED = 36;
-  SET_KEYGUARD_DISABLED = 37;
-  SET_STATUS_BAR_DISABLED = 38;
-  SET_ORGANIZATION_COLOR = 39;
-  SET_PROFILE_NAME = 40;
-  SET_USER_ICON = 41;
-  SET_DEVICE_OWNER_LOCK_SCREEN_INFO = 42;
-  SET_SHORT_SUPPORT_MESSAGE = 43;
-  SET_LONG_SUPPORT_MESSAGE = 44;
-  SET_CROSS_PROFILE_CONTACTS_SEARCH_DISABLED = 45;
-  SET_CROSS_PROFILE_CALLER_ID_DISABLED = 46;
-  SET_BLUETOOTH_CONTACT_SHARING_DISABLED = 47;
-  ADD_CROSS_PROFILE_INTENT_FILTER = 48;
-  ADD_CROSS_PROFILE_WIDGET_PROVIDER = 49;
-  SET_SYSTEM_UPDATE_POLICY = 50;
-  SET_LOCKTASK_MODE_ENABLED = 51;
-  ADD_PERSISTENT_PREFERRED_ACTIVITY = 52;
-  REQUEST_BUGREPORT = 53;
-  GET_WIFI_MAC_ADDRESS = 54;
-  REQUEST_QUIET_MODE_ENABLED = 55;
-  WORK_PROFILE_LOCATION_CHANGED = 56;
-  DO_USER_INFO_CLICKED = 57;
-  TRANSFER_OWNERSHIP = 58;
-  GENERATE_KEY_PAIR = 59;
-  SET_KEY_PAIR_CERTIFICATE = 60;
-  SET_KEEP_UNINSTALLED_PACKAGES = 61;
-  SET_APPLICATION_RESTRICTIONS = 62;
-  SET_APPLICATION_HIDDEN = 63;
-  ENABLE_SYSTEM_APP = 64;
-  ENABLE_SYSTEM_APP_WITH_INTENT = 65;
-  INSTALL_EXISTING_PACKAGE = 66;
-  SET_UNINSTALL_BLOCKED = 67;
-  SET_PACKAGES_SUSPENDED = 68;
-  ON_LOCK_TASK_MODE_ENTERING = 69;
-  SET_CROSS_PROFILE_CALENDAR_PACKAGES = 70;
-  GET_USER_PASSWORD_COMPLEXITY_LEVEL = 72;
-  INSTALL_SYSTEM_UPDATE = 73;
-  INSTALL_SYSTEM_UPDATE_ERROR = 74;
-  IS_MANAGED_KIOSK = 75;
-  IS_UNATTENDED_MANAGED_KIOSK = 76;
-  PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 77;
-  PROVISIONING_PERSISTENT_DEVICE_OWNER = 78;
-
-  // existing Tron logs to be migrated to statsd
-  PROVISIONING_ENTRY_POINT_NFC = 79;
-  PROVISIONING_ENTRY_POINT_QR_CODE = 80;
-  PROVISIONING_ENTRY_POINT_CLOUD_ENROLLMENT = 81;
-  PROVISIONING_ENTRY_POINT_ADB = 82;
-  PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE = 83;
-  PROVISIONING_DPC_PACKAGE_NAME = 84;
-  PROVISIONING_DPC_INSTALLED_BY_PACKAGE = 85;
-  PROVISIONING_PROVISIONING_ACTIVITY_TIME_MS = 86;
-  PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS = 87;
-  PROVISIONING_ENCRYPT_DEVICE_ACTIVITY_TIME_MS = 88;
-  PROVISIONING_WEB_ACTIVITY_TIME_MS = 89;
-  PROVISIONING_TRAMPOLINE_ACTIVITY_TIME_MS = 90 [deprecated=true];
-  PROVISIONING_POST_ENCRYPTION_ACTIVITY_TIME_MS = 91 [deprecated=true];
-  PROVISIONING_FINALIZATION_ACTIVITY_TIME_MS = 92 [deprecated=true];
-  PROVISIONING_NETWORK_TYPE = 93;
-  PROVISIONING_ACTION = 94;
-  PROVISIONING_EXTRAS = 95;
-  PROVISIONING_COPY_ACCOUNT_TASK_MS = 96;
-  PROVISIONING_CREATE_PROFILE_TASK_MS = 97;
-  PROVISIONING_START_PROFILE_TASK_MS = 98;
-  PROVISIONING_DOWNLOAD_PACKAGE_TASK_MS = 99;
-  PROVISIONING_INSTALL_PACKAGE_TASK_MS = 100;
-  PROVISIONING_CANCELLED = 101;
-  PROVISIONING_ERROR = 102;
-  PROVISIONING_COPY_ACCOUNT_STATUS = 103;
-  PROVISIONING_TOTAL_TASK_TIME_MS = 104;
-  PROVISIONING_SESSION_STARTED = 105;
-  PROVISIONING_SESSION_COMPLETED = 106;
-  PROVISIONING_TERMS_ACTIVITY_TIME_MS = 107;
-  PROVISIONING_TERMS_COUNT = 108;
-  PROVISIONING_TERMS_READ = 109;
-
-  SEPARATE_PROFILE_CHALLENGE_CHANGED = 110;
-  SET_GLOBAL_SETTING = 111;
-  INSTALL_PACKAGE = 112;
-  UNINSTALL_PACKAGE = 113;
-  WIFI_SERVICE_ADD_NETWORK_SUGGESTIONS = 114;
-  WIFI_SERVICE_ADD_OR_UPDATE_NETWORK = 115;
-  QUERY_SUMMARY_FOR_DEVICE = 116;
-  REMOVE_CROSS_PROFILE_WIDGET_PROVIDER = 117;
-  ESTABLISH_VPN = 118;
-  SET_NETWORK_LOGGING_ENABLED = 119;
-  RETRIEVE_NETWORK_LOGS = 120;
-  PROVISIONING_PREPARE_TOTAL_TIME_MS = 121;
-  PROVISIONING_PREPARE_STARTED = 122;
-  PROVISIONING_PREPARE_COMPLETED = 123;
-  PROVISIONING_FLOW_TYPE = 124;
-  CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES = 125;
-  CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER = 126;
-  SET_AUTO_TIME = 127;
-  SET_AUTO_TIME_ZONE = 128;
-  SET_USER_CONTROL_DISABLED_PACKAGES = 129;
-  SET_FACTORY_RESET_PROTECTION = 130;
-  SET_COMMON_CRITERIA_MODE = 131;
-  ALLOW_MODIFICATION_OF_ADMIN_CONFIGURED_NETWORKS = 132;
-  SET_TIME = 133;
-  SET_TIME_ZONE = 134;
-  SET_PERSONAL_APPS_SUSPENDED = 135;
-  SET_MANAGED_PROFILE_MAXIMUM_TIME_OFF = 136;
-  COMP_TO_ORG_OWNED_PO_MIGRATED = 137;
-  SET_CROSS_PROFILE_PACKAGES = 138;
-  SET_INTERACT_ACROSS_PROFILES_APP_OP = 139;
-  GET_CROSS_PROFILE_PACKAGES = 140;
-  CAN_REQUEST_INTERACT_ACROSS_PROFILES_TRUE = 141;
-  CAN_REQUEST_INTERACT_ACROSS_PROFILES_FALSE_NO_PROFILES = 142;
-  CAN_REQUEST_INTERACT_ACROSS_PROFILES_FALSE_WHITELIST = 143;
-  CAN_REQUEST_INTERACT_ACROSS_PROFILES_FALSE_PERMISSION = 144;
-  CAN_INTERACT_ACROSS_PROFILES_TRUE = 145;
-  CAN_INTERACT_ACROSS_PROFILES_FALSE_PERMISSION = 146;
-  CAN_INTERACT_ACROSS_PROFILES_FALSE_NO_PROFILES = 147;
-  CREATE_CROSS_PROFILE_INTENT = 148;
-  IS_MANAGED_PROFILE = 149;
-  START_ACTIVITY_BY_INTENT = 150;
-  BIND_CROSS_PROFILE_SERVICE = 151;
-  PROVISIONING_DPC_SETUP_STARTED = 152;
-  PROVISIONING_DPC_SETUP_COMPLETED = 153;
-  PROVISIONING_ORGANIZATION_OWNED_MANAGED_PROFILE = 154;
-  RESOLVER_CROSS_PROFILE_TARGET_OPENED = 155;
-  RESOLVER_SWITCH_TABS = 156;
-  RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED = 157;
-  RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL= 158;
-  RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK= 159;
-  RESOLVER_EMPTY_STATE_NO_APPS_RESOLVED= 160;
-  RESOLVER_AUTOLAUNCH_CROSS_PROFILE_TARGET = 161;
-  CROSS_PROFILE_SETTINGS_PAGE_LAUNCHED_FROM_APP = 162;
-  CROSS_PROFILE_SETTINGS_PAGE_LAUNCHED_FROM_SETTINGS = 163;
-  CROSS_PROFILE_SETTINGS_PAGE_ADMIN_RESTRICTED = 164;
-  CROSS_PROFILE_SETTINGS_PAGE_MISSING_WORK_APP = 165;
-  CROSS_PROFILE_SETTINGS_PAGE_MISSING_PERSONAL_APP = 166;
-  CROSS_PROFILE_SETTINGS_PAGE_MISSING_INSTALL_BANNER_INTENT = 167;
-  CROSS_PROFILE_SETTINGS_PAGE_INSTALL_BANNER_CLICKED = 168;
-  CROSS_PROFILE_SETTINGS_PAGE_INSTALL_BANNER_NO_INTENT_CLICKED  = 169;
-  CROSS_PROFILE_SETTINGS_PAGE_USER_CONSENTED = 170;
-  CROSS_PROFILE_SETTINGS_PAGE_USER_DECLINED_CONSENT = 171;
-  CROSS_PROFILE_SETTINGS_PAGE_PERMISSION_REVOKED = 172;
-  DOCSUI_EMPTY_STATE_NO_PERMISSION = 173;
-  DOCSUI_EMPTY_STATE_QUIET_MODE = 174;
-  DOCSUI_LAUNCH_OTHER_APP = 175;
-  DOCSUI_PICK_RESULT = 176;
-}
diff --git a/core/proto/android/stats/devicepolicy/jarjar-rules.txt b/core/proto/android/stats/devicepolicy/jarjar-rules.txt
deleted file mode 100644
index 40043a86..0000000
--- a/core/proto/android/stats/devicepolicy/jarjar-rules.txt
+++ /dev/null
@@ -1 +0,0 @@
-rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
diff --git a/core/proto/android/stats/dnsresolver/Android.bp b/core/proto/android/stats/dnsresolver/Android.bp
deleted file mode 100644
index 1e8c763..0000000
--- a/core/proto/android/stats/dnsresolver/Android.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library_static {
-    name: "dnsresolverprotosnano",
-    proto: {
-        type: "nano",
-    },
-    srcs: [
-        "dns_resolver.proto",
-    ],
-    sdk_version: "system_current",
-}
diff --git a/core/proto/android/stats/dnsresolver/dns_resolver.proto b/core/proto/android/stats/dnsresolver/dns_resolver.proto
deleted file mode 100644
index b17d12c..0000000
--- a/core/proto/android/stats/dnsresolver/dns_resolver.proto
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-syntax = "proto2";
-package android.stats.dnsresolver;
-
-enum EventType {
-    EVENT_UNKNOWN = 0;
-    EVENT_GETADDRINFO = 1;
-    EVENT_GETHOSTBYNAME = 2;
-    EVENT_GETHOSTBYADDR = 3;
-    EVENT_RES_NSEND = 4;
-}
-
-// The return value of the DNS resolver for each DNS lookups.
-// bionic/libc/include/netdb.h
-// system/netd/resolv/include/netd_resolv/resolv.h
-enum ReturnCode {
-    RC_EAI_NO_ERROR = 0;
-    RC_EAI_ADDRFAMILY = 1;
-    RC_EAI_AGAIN = 2;
-    RC_EAI_BADFLAGS = 3;
-    RC_EAI_FAIL = 4;
-    RC_EAI_FAMILY = 5;
-    RC_EAI_MEMORY = 6;
-    RC_EAI_NODATA = 7;
-    RC_EAI_NONAME = 8;
-    RC_EAI_SERVICE = 9;
-    RC_EAI_SOCKTYPE = 10;
-    RC_EAI_SYSTEM = 11;
-    RC_EAI_BADHINTS = 12;
-    RC_EAI_PROTOCOL = 13;
-    RC_EAI_OVERFLOW = 14;
-    RC_RESOLV_INTERNAL_ERROR = 254;
-    RC_RESOLV_TIMEOUT = 255;
-    RC_EAI_MAX = 256;
-}
-
-enum NsRcode {
-    NS_R_NO_ERROR = 0;  // No error occurred.
-    NS_R_FORMERR = 1;   // Format error.
-    NS_R_SERVFAIL = 2;  // Server failure.
-    NS_R_NXDOMAIN = 3;  // Name error.
-    NS_R_NOTIMPL = 4;   // Unimplemented.
-    NS_R_REFUSED = 5;   // Operation refused.
-    // these are for BIND_UPDATE
-    NS_R_YXDOMAIN = 6;  // Name exists
-    NS_R_YXRRSET = 7;   // RRset exists
-    NS_R_NXRRSET = 8;   // RRset does not exist
-    NS_R_NOTAUTH = 9;   // Not authoritative for zone
-    NS_R_NOTZONE = 10;  // Zone of record different from zone section
-    NS_R_MAX = 11;
-    // Define rcode=12~15(UNASSIGNED) in rcode enum type.
-    // Some DNS Servers might return undefined code to devices.
-    // Without the enum definition, that would be noise for our dashboard.
-    NS_R_UNASSIGNED12 = 12; // Unassigned
-    NS_R_UNASSIGNED13 = 13; // Unassigned
-    NS_R_UNASSIGNED14 = 14; // Unassigned
-    NS_R_UNASSIGNED15 = 15; // Unassigned
-    // The following are EDNS extended rcodes
-    NS_R_BADVERS = 16;
-    // The following are TSIG errors
-    // NS_R_BADSIG  = 16,
-    NS_R_BADKEY = 17;
-    NS_R_BADTIME = 18;
-    NS_R_INTERNAL_ERROR = 254;
-    NS_R_TIMEOUT = 255;
-}
-
-// Currently defined type values for resources and queries.
-enum NsType {
-    NS_T_INVALID = 0;      // Cookie.
-    NS_T_A = 1;            // Host address.
-    NS_T_NS = 2;           // Authoritative server.
-    NS_T_MD = 3;           // Mail destination.
-    NS_T_MF = 4;           // Mail forwarder.
-    NS_T_CNAME = 5;        // Canonical name.
-    NS_T_SOA = 6;          // Start of authority zone.
-    NS_T_MB = 7;           // Mailbox domain name.
-    NS_T_MG = 8;           // Mail group member.
-    NS_T_MR = 9;           // Mail rename name.
-    NS_T_NULL = 10;        // Null resource record.
-    NS_T_WKS = 11;         // Well known service.
-    NS_T_PTR = 12;         // Domain name pointer.
-    NS_T_HINFO = 13;       // Host information.
-    NS_T_MINFO = 14;       // Mailbox information.
-    NS_T_MX = 15;          // Mail routing information.
-    NS_T_TXT = 16;         // Text strings.
-    NS_T_RP = 17;          // Responsible person.
-    NS_T_AFSDB = 18;       // AFS cell database.
-    NS_T_X25 = 19;         // X_25 calling address.
-    NS_T_ISDN = 20;        // ISDN calling address.
-    NS_T_RT = 21;          // Router.
-    NS_T_NSAP = 22;        // NSAP address.
-    NS_T_NSAP_PTR = 23;    // Reverse NSAP lookup (deprecated).
-    NS_T_SIG = 24;         // Security signature.
-    NS_T_KEY = 25;         // Security key.
-    NS_T_PX = 26;          // X.400 mail mapping.
-    NS_T_GPOS = 27;        // Geographical position (withdrawn).
-    NS_T_AAAA = 28;        // IPv6 Address.
-    NS_T_LOC = 29;         // Location Information.
-    NS_T_NXT = 30;         // Next domain (security).
-    NS_T_EID = 31;         // Endpoint identifier.
-    NS_T_NIMLOC = 32;      // Nimrod Locator.
-    NS_T_SRV = 33;         // Server Selection.
-    NS_T_ATMA = 34;        // ATM Address
-    NS_T_NAPTR = 35;       // Naming Authority PoinTeR
-    NS_T_KX = 36;          // Key Exchange
-    NS_T_CERT = 37;        // Certification record
-    NS_T_A6 = 38;          // IPv6 address (experimental)
-    NS_T_DNAME = 39;       // Non-terminal DNAME
-    NS_T_SINK = 40;        // Kitchen sink (experimentatl)
-    NS_T_OPT = 41;         // EDNS0 option (meta-RR)
-    NS_T_APL = 42;         // Address prefix list (RFC 3123)
-    NS_T_DS = 43;          // Delegation Signer
-    NS_T_SSHFP = 44;       // SSH Fingerprint
-    NS_T_IPSECKEY = 45;    // IPSEC Key
-    NS_T_RRSIG = 46;       // RRset Signature
-    NS_T_NSEC = 47;        // Negative security
-    NS_T_DNSKEY = 48;      // DNS Key
-    NS_T_DHCID = 49;       // Dynamic host configuratin identifier
-    NS_T_NSEC3 = 50;       // Negative security type 3
-    NS_T_NSEC3PARAM = 51;  // Negative security type 3 parameters
-    NS_T_HIP = 55;         // Host Identity Protocol
-    NS_T_SPF = 99;         // Sender Policy Framework
-    NS_T_TKEY = 249;       // Transaction key
-    NS_T_TSIG = 250;       // Transaction signature.
-    NS_T_IXFR = 251;       // Incremental zone transfer.
-    NS_T_AXFR = 252;       // Transfer zone of authority.
-    NS_T_MAILB = 253;      // Transfer mailbox records.
-    NS_T_MAILA = 254;      // Transfer mail agent records.
-    NS_T_ANY = 255;        // Wildcard match.
-    NS_T_ZXFR = 256;       // BIND-specific, nonstandard.
-    NS_T_DLV = 32769;      // DNSSEC look-aside validatation.
-    NS_T_MAX = 65536;
-}
-
-enum IpVersion {
-    IV_UNKNOWN = 0;
-    IV_IPV4 = 1;
-    IV_IPV6 = 2;
-}
-
-enum Protocol {
-    PROTO_UNKNOWN = 0;
-    PROTO_UDP = 1;
-    PROTO_TCP = 2;
-    PROTO_DOT = 3;
-}
-
-enum PrivateDnsModes {
-    PDM_UNKNOWN = 0;
-    PDM_OFF = 1;
-    PDM_OPPORTUNISTIC = 2;
-    PDM_STRICT = 3;
-}
-
-enum NetworkType {
-    NT_UNKNOWN = 0;
-    // Indicates this network uses a Cellular transport.
-    NT_CELLULAR = 1;
-    // Indicates this network uses a Wi-Fi transport.
-    NT_WIFI = 2;
-    // Indicates this network uses a Bluetooth transport.
-    NT_BLUETOOTH = 3;
-    // Indicates this network uses an Ethernet transport.
-    NT_ETHERNET = 4;
-    // Indicates this network uses a VPN transport, now deprecated.
-    NT_VPN = 5 [deprecated=true];
-    // Indicates this network uses a Wi-Fi Aware transport.
-    NT_WIFI_AWARE = 6;
-    // Indicates this network uses a LoWPAN transport.
-    NT_LOWPAN = 7;
-    // Indicates this network uses a Cellular+VPN transport.
-    NT_CELLULAR_VPN = 8;
-    // Indicates this network uses a Wi-Fi+VPN transport.
-    NT_WIFI_VPN = 9;
-    // Indicates this network uses a Bluetooth+VPN transport.
-    NT_BLUETOOTH_VPN = 10;
-    // Indicates this network uses an Ethernet+VPN transport.
-    NT_ETHERNET_VPN = 11;
-    // Indicates this network uses a Wi-Fi+Cellular+VPN transport.
-    NT_WIFI_CELLULAR_VPN = 12;
-}
-
-enum CacheStatus{
-    // the cache can't handle that kind of queries.
-    // or the answer buffer is too small.
-    CS_UNSUPPORTED = 0;
-    // the cache doesn't know about this query.
-    CS_NOTFOUND = 1;
-    // the cache found the answer.
-    CS_FOUND = 2;
-    // Don't do anything on cache.
-    CS_SKIP = 3;
-}
-
-// The enum LinuxErrno is defined in the following 2 files.
-// 1. bionic/libc/kernel/uapi/asm-generic/errno-base.h
-// 2. bionic/libc/kernel/uapi/asm-generic/errno.h
-enum LinuxErrno {
-    SYS_NO_ERROR = 0;
-    SYS_EPERM = 1;              // Not super-user
-    SYS_ENOENT = 2;             // No such file or directory
-    SYS_ESRCH = 3;              // No such process
-    SYS_EINTR = 4;              // Interrupted system call
-    SYS_EIO = 5;                // I/O error
-    SYS_ENXIO = 6;              // No such device or address
-    SYS_E2BIG = 7;              // Arg list too long
-    SYS_ENOEXEC = 8;            // Exec format error
-    SYS_EBADF = 9;              // Bad file number
-    SYS_ECHILD = 10;            // No children
-    SYS_EAGAIN = 11;            // No more processes
-    SYS_ENOMEM = 12;            // Not enough core
-    SYS_EACCES = 13;            // Permission denied
-    SYS_EFAULT = 14;            // Bad address
-    SYS_ENOTBLK = 15;           // Block device required
-    SYS_EBUSY = 16;             // Mount device busy
-    SYS_EEXIST = 17;            // File exists
-    SYS_EXDEV = 18;             // Cross-device link
-    SYS_ENODEV = 19;            // No such device
-    SYS_ENOTDIR = 20;           // Not a directory
-    SYS_EISDIR = 21;            // Is a directory
-    SYS_EINVAL = 22;            // Invalid argument
-    SYS_ENFILE = 23;            // Too many open files in system
-    SYS_EMFILE = 24;            // Too many open files
-    SYS_ENOTTY = 25;            // Not a typewriter
-    SYS_ETXTBSY = 26;           // Text file busy
-    SYS_EFBIG = 27;             // File too large
-    SYS_ENOSPC = 28;            // No space left on device
-    SYS_ESPIPE = 29;            // Illegal seek
-    SYS_EROFS = 30;             // Read only file system
-    SYS_EMLINK = 31;            // Too many links
-    SYS_EPIPE = 32;             // Broken pipe
-    SYS_EDOM = 33;              // Math arg out of domain of func
-    SYS_ERANGE = 34;            // Math result not representable
-    SYS_EDEADLOCK = 35;         // File locking deadlock error
-    SYS_ENAMETOOLONG = 36;      // File or path name too long
-    SYS_ENOLCK = 37;            // No record locks available
-    SYS_ENOSYS = 38;            // Function not implemented
-    SYS_ENOTEMPTY = 39;         // Directory not empty
-    SYS_ELOOP = 40;             // Too many symbolic links
-    SYS_ENOMSG = 42;            // No message of desired type
-    SYS_EIDRM = 43;             // Identifier removed
-    SYS_ECHRNG = 44;            // Channel number out of range
-    SYS_EL2NSYNC = 45;          // Level 2 not synchronized
-    SYS_EL3HLT = 46;            // Level 3 halted
-    SYS_EL3RST = 47;            // Level 3 reset
-    SYS_ELNRNG = 48;            // Link number out of range
-    SYS_EUNATCH = 49;           // rotocol driver not attached
-    SYS_ENOCSI = 50;            // No CSI structure available
-    SYS_EL2HLT = 51;            // Level 2 halted
-    SYS_EBADE = 52;             // Invalid exchange
-    SYS_EBADR = 53;             // Invalid request descriptor
-    SYS_EXFULL = 54;            // Exchange full
-    SYS_ENOANO = 55;            // No anode
-    SYS_EBADRQC = 56;           // Invalid request code
-    SYS_EBADSLT = 57;           // Invalid slot
-    SYS_EBFONT = 59;            // Bad font file fmt
-    SYS_ENOSTR = 60;            // Device not a stream
-    SYS_ENODATA = 61;           // No data (for no delay io)
-    SYS_ETIME = 62;             // Timer expired
-    SYS_ENOSR = 63;             // Out of streams resources
-    SYS_ENONET = 64;            // Machine is not on the network
-    SYS_ENOPKG = 65;            // Package not installed
-    SYS_EREMOTE = 66;           // The object is remote
-    SYS_ENOLINK = 67;           // The link has been severed
-    SYS_EADV = 68;              // Advertise error
-    SYS_ESRMNT = 69;            // Srmount error
-    SYS_ECOMM = 70;             // Communication error on send
-    SYS_EPROTO = 71;            // Protocol error
-    SYS_EMULTIHOP = 72;         // Multihop attempted
-    SYS_EDOTDOT = 73;           // Cross mount point (not really error)
-    SYS_EBADMSG = 74;           // Trying to read unreadable message
-    SYS_EOVERFLOW = 75;         // Value too large for defined data type
-    SYS_ENOTUNIQ = 76;          // Given log. name not unique
-    SYS_EBADFD = 77;            // f.d. invalid for this operation
-    SYS_EREMCHG = 78;           // Remote address changed
-    SYS_ELIBACC = 79;           // Can't access a needed shared lib
-    SYS_ELIBBAD = 80;           // Accessing a corrupted shared lib
-    SYS_ELIBSCN = 81;           // .lib section in a.out corrupted
-    SYS_ELIBMAX = 82;           // Attempting to link in too many libs
-    SYS_ELIBEXEC = 83;          // Attempting to exec a shared library
-    SYS_EILSEQ = 84;
-    SYS_ERESTART = 85;
-    SYS_ESTRPIPE = 86;
-    SYS_EUSERS = 87;
-    SYS_ENOTSOCK = 88;          // Socket operation on non-socket
-    SYS_EDESTADDRREQ = 89;      // Destination address required
-    SYS_EMSGSIZE = 90;          // Message too long
-    SYS_EPROTOTYPE = 91;        // Protocol wrong type for socket
-    SYS_ENOPROTOOPT = 92;       // Protocol not available
-    SYS_EPROTONOSUPPORT = 93;   // Unknown protocol
-    SYS_ESOCKTNOSUPPORT = 94;   // Socket type not supported
-    SYS_EOPNOTSUPP = 95;        // Operation not supported on transport endpoint
-    SYS_EPFNOSUPPORT = 96;      // Protocol family not supported
-    SYS_EAFNOSUPPORT = 97;      // Address family not supported by protocol family
-    SYS_EADDRINUSE = 98;        // Address already in use
-    SYS_EADDRNOTAVAIL = 99;     // Address not available
-    SYS_ENETDOWN = 100;         // Network interface is not configured
-    SYS_ENETUNREACH = 101;      // Network is unreachable
-    SYS_ENETRESET = 102;
-    SYS_ECONNABORTED = 103;     // Connection aborted
-    SYS_ECONNRESET = 104;       // Connection reset by peer
-    SYS_ENOBUFS = 105;          // No buffer space available
-    SYS_EISCONN = 106;          // Socket is already connected
-    SYS_ENOTCONN = 107;         // Socket is not connected
-    SYS_ESHUTDOWN = 108;        // Can't send after socket shutdown
-    SYS_ETOOMANYREFS = 109;
-    SYS_ETIMEDOUT = 110;        // Connection timed out
-    SYS_ECONNREFUSED = 111;     // Connection refused
-    SYS_EHOSTDOWN = 112;        // Host is down
-    SYS_EHOSTUNREACH = 113;     // Host is unreachable
-    SYS_EALREADY = 114;         // Socket already connected
-    SYS_EINPROGRESS = 115;      // Connection already in progress
-    SYS_ESTALE = 116;
-    SYS_EUCLEAN = 117;
-    SYS_ENOTNAM = 118;
-    SYS_ENAVAIL = 119;
-    SYS_EISNAM = 120;
-    SYS_EREMOTEIO = 121;
-    SYS_EDQUOT = 122;
-    SYS_ENOMEDIUM = 123;        // No medium (in tape drive)
-    SYS_EMEDIUMTYPE = 124;
-    SYS_ECANCELED = 125;
-    SYS_ENOKEY = 126;
-    SYS_EKEYEXPIRED = 127;
-    SYS_EKEYREVOKED = 128;
-    SYS_EKEYREJECTED = 129;
-    SYS_EOWNERDEAD = 130;
-    SYS_ENOTRECOVERABLE = 131;
-    SYS_ERFKILL = 132;
-    SYS_EHWPOISON = 133;
-}
-
-message DnsQueryEvent {
-    optional android.stats.dnsresolver.NsRcode rcode = 1;
-
-    optional android.stats.dnsresolver.NsType type = 2;
-
-    optional android.stats.dnsresolver.CacheStatus cache_hit = 3;
-
-    optional android.stats.dnsresolver.IpVersion ip_version = 4;
-
-    optional android.stats.dnsresolver.Protocol protocol = 5;
-
-    // Number of DNS query retry times
-    optional int32 retry_times = 6;
-
-    // Ordinal number of name server.
-    optional int32 dns_server_index = 7;
-
-    // Used only by TCP and DOT. True for new connections.
-    optional bool connected = 8;
-
-    optional int32 latency_micros = 9;
-
-    optional android.stats.dnsresolver.LinuxErrno linux_errno = 10;
-}
-
-message DnsQueryEvents {
-    repeated DnsQueryEvent dns_query_event = 1;
-}
diff --git a/core/proto/android/stats/docsui/docsui_enums.proto b/core/proto/android/stats/docsui/docsui_enums.proto
deleted file mode 100644
index 5963f6a..0000000
--- a/core/proto/android/stats/docsui/docsui_enums.proto
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.stats.docsui;
-option java_multiple_files = true;
-
-enum LaunchAction {
-    UNKNOWN = 0;
-    OPEN = 1;
-    CREATE = 2;
-    GET_CONTENT = 3;
-    OPEN_TREE = 4;
-    PICK_COPY_DEST = 5;
-    BROWSE = 6;
-    OTHER = 7;
-}
-
-enum MimeType {
-    MIME_UNKNOWN = 0;
-    MIME_NONE = 1;
-    MIME_ANY = 2;
-    MIME_APPLICATION = 3;
-    MIME_AUDIO = 4;
-    MIME_IMAGE = 5;
-    MIME_MESSAGE = 6;
-    MIME_MULTIPART = 7;
-    MIME_TEXT = 8;
-    MIME_VIDEO = 9;
-    MIME_OTHER = 10;
-}
-
-enum Root {
-    ROOT_UNKNOWN = 0;
-    ROOT_NONE = 1;
-    ROOT_OTHER_DOCS_PROVIDER = 2;
-    ROOT_AUDIO = 3;
-    ROOT_DEVICE_STORAGE = 4;
-    ROOT_DOWNLOADS = 5;
-    ROOT_HOME = 6;
-    ROOT_IMAGES = 7;
-    ROOT_RECENTS = 8;
-    ROOT_VIDEOS = 9;
-    ROOT_MTP = 10;
-    ROOT_THIRD_PARTY_APP = 11;
-    ROOT_DOCUMENTS = 12;
-}
-
-enum ContextScope {
-    SCOPE_UNKNOWN = 0;
-    SCOPE_FILES = 1;
-    SCOPE_PICKER = 2;
-}
-
-enum Provider {
-    PROVIDER_UNKNOWN = 0;
-    PROVIDER_SYSTEM = 1;
-    PROVIDER_EXTERNAL = 2;
-}
-
-enum FileOperation {
-    OP_UNKNOWN = 0;
-    OP_OTHER = 1;
-    OP_COPY = 2;
-    OP_COPY_INTRA_PROVIDER = 3;
-    OP_COPY_SYSTEM_PROVIDER = 4;
-    OP_COPY_EXTERNAL_PROVIDER = 5;
-    OP_MOVE = 6;
-    OP_MOVE_INTRA_PROVIDER = 7;
-    OP_MOVE_SYSTEM_PROVIDER = 8;
-    OP_MOVE_EXTERNAL_PROVIDER = 9;
-    OP_DELETE = 10;
-    OP_RENAME = 11;
-    OP_CREATE_DIR = 12;
-    OP_OTHER_ERROR = 13;
-    OP_DELETE_ERROR = 14;
-    OP_MOVE_ERROR = 15;
-    OP_COPY_ERROR = 16;
-    OP_RENAME_ERROR = 17;
-    OP_CREATE_DIR_ERROR = 18;
-    OP_COMPRESS_INTRA_PROVIDER = 19;
-    OP_COMPRESS_SYSTEM_PROVIDER = 20;
-    OP_COMPRESS_EXTERNAL_PROVIDER = 21;
-    OP_EXTRACT_INTRA_PROVIDER = 22;
-    OP_EXTRACT_SYSTEM_PROVIDER = 23;
-    OP_EXTRACT_EXTERNAL_PROVIDER = 24;
-    OP_COMPRESS_ERROR = 25;
-    OP_EXTRACT_ERROR = 26;
-}
-
-enum SubFileOperation {
-    SUB_OP_UNKNOWN = 0;
-    SUB_OP_QUERY_DOC = 1;
-    SUB_OP_QUERY_CHILD = 2;
-    SUB_OP_OPEN_FILE = 3;
-    SUB_OP_READ_FILE = 4;
-    SUB_OP_CREATE_DOC = 5;
-    SUB_OP_WRITE_FILE = 6;
-    SUB_OP_DELETE_DOC = 7;
-    SUB_OP_OBTAIN_STREAM_TYPE = 8;
-    SUB_OP_QUICK_MOVE = 9;
-    SUB_OP_QUICK_COPY = 10;
-}
-
-enum CopyMoveOpMode {
-    MODE_UNKNOWN = 0;
-    MODE_PROVIDER = 1;
-    MODE_CONVERTED = 2;
-    MODE_CONVENTIONAL = 3;
-}
-
-enum Authority {
-    AUTH_UNKNOWN = 0;
-    AUTH_OTHER = 1;
-    AUTH_MEDIA = 2;
-    AUTH_STORAGE_INTERNAL = 3;
-    AUTH_STORAGE_EXTERNAL = 4;
-    AUTH_DOWNLOADS = 5;
-    AUTH_MTP = 6;
-}
-
-enum UserAction {
-    ACTION_UNKNOWN = 0;
-    ACTION_OTHER = 1;
-    ACTION_GRID = 2;
-    ACTION_LIST = 3;
-    ACTION_SORT_NAME = 4;
-    ACTION_SORT_DATE = 5;
-    ACTION_SORT_SIZE = 6;
-    ACTION_SORT_TYPE = 7;
-    ACTION_SEARCH = 8;
-    ACTION_SHOW_SIZE = 9;
-    ACTION_HIDE_SIZE = 10;
-    ACTION_SETTINGS = 11;
-    ACTION_COPY_TO = 12;
-    ACTION_MOVE_TO = 13;
-    ACTION_DELETE = 14;
-    ACTION_RENAME = 15;
-    ACTION_CREATE_DIR = 16;
-    ACTION_SELECT_ALL = 17;
-    ACTION_SHARE = 18;
-    ACTION_OPEN = 19;
-    ACTION_SHOW_ADVANCED = 20;
-    ACTION_HIDE_ADVANCED = 21;
-    ACTION_NEW_WINDOW = 22;
-    ACTION_PASTE_CLIPBOARD = 23;
-    ACTION_COPY_CLIPBOARD = 24;
-    ACTION_DRAG_N_DROP = 25;
-    ACTION_DRAG_N_DROP_MULTI_WINDOW = 26;
-    ACTION_CUT_CLIPBOARD = 27;
-    ACTION_COMPRESS = 28;
-    ACTION_EXTRACT_TO = 29;
-    ACTION_VIEW_IN_APPLICATION = 30;
-    ACTION_INSPECTOR = 31;
-    ACTION_SEARCH_CHIP = 32;
-    ACTION_SEARCH_HISTORY = 33;
-}
-
-enum InvalidScopedAccess {
-    SCOPED_DIR_ACCESS_UNKNOWN = 0;
-    SCOPED_DIR_ACCESS_INVALID_ARGUMENTS = 1;
-    SCOPED_DIR_ACCESS_INVALID_DIRECTORY = 2;
-    SCOPED_DIR_ACCESS_ERROR = 3;
-    SCOPED_DIR_ACCESS_DEPRECATED = 4;
-}
-
-enum SearchType {
-    TYPE_UNKNOWN = 0;
-    TYPE_CHIP_IMAGES = 1;
-    TYPE_CHIP_AUDIOS = 2;
-    TYPE_CHIP_VIDEOS = 3;
-    TYPE_CHIP_DOCS = 4;
-    TYPE_SEARCH_HISTORY = 5;
-    TYPE_SEARCH_STRING = 6;
-    TYPE_CHIP_LARGE_FILES = 7;
-    TYPE_CHIP_FROM_THIS_WEEK = 8;
-}
-
-enum SearchMode {
-    SEARCH_UNKNOWN = 0;
-    SEARCH_KEYWORD = 1;
-    SEARCH_CHIPS = 2;
-    SEARCH_KEYWORD_N_CHIPS = 3;
-}
diff --git a/core/proto/android/stats/enums.proto b/core/proto/android/stats/enums.proto
deleted file mode 100644
index 8f8055e..0000000
--- a/core/proto/android/stats/enums.proto
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats;
-option java_outer_classname = "StatsEnums";
-
-enum EventType {
-  // Unknown.
-  TYPE_UNKNOWN = 0;
-  CONTENT_SUGGESTIONS_CLASSIFY_CONTENT_CALL_SUCCEEDED = 1;
-  CONTENT_SUGGESTIONS_CLASSIFY_CONTENT_CALL_FAILED = 2;
-  CONTENT_SUGGESTIONS_SUGGEST_CONTENT_CALL_SUCCEEDED = 3;
-  CONTENT_SUGGESTIONS_SUGGEST_CONTENT_CALL_FAILED = 4;
-}
diff --git a/core/proto/android/stats/hdmi/enums.proto b/core/proto/android/stats/hdmi/enums.proto
deleted file mode 100644
index acb8899..0000000
--- a/core/proto/android/stats/hdmi/enums.proto
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.hdmi;
-option java_multiple_files = true;
-option java_outer_classname = "HdmiStatsEnums";
-
-// HDMI CEC logical addresses.
-// Values correspond to "CEC Table 5 Logical Addresses" in the HDMI CEC 1.4b spec.
-enum LogicalAddress {
-    LOGICAL_ADDRESS_UNKNOWN = -1;
-    TV = 0;
-    RECORDING_DEVICE_1 = 1;
-    RECORDING_DEVICE_2 = 2;
-    TUNER_1 = 3;
-    PLAYBACK_DEVICE_1 = 4;
-    AUDIO_SYSTEM = 5;
-    TUNER_2 = 6;
-    TUNER_3 = 7;
-    PLAYBACK_DEVICE_2 = 8;
-    RECORDING_DEVICE_3 = 9;
-    TUNER_4 = 10;
-    PLAYBACK_DEVICE_3 = 11;
-    RESERVED_1 = 12;
-    RESERVED_2 = 13;
-    SPECIFIC_USE = 14;
-    UNREGISTERED_OR_BROADCAST = 15;
-}
-
-// The relationship between two paths.
-// Values correspond exactly to PathRelationship in com.android.server.hdmi.Constants.
-enum PathRelationship {
-    RELATIONSHIP_TO_ACTIVE_SOURCE_UNKNOWN = 0;
-    DIFFERENT_BRANCH = 1;
-    ANCESTOR = 2;
-    DESCENDANT = 3;
-    SIBLING = 4;
-    SAME = 5;
-}
-
-// The result of attempting to send a HDMI CEC message.
-// Values correspond to the constants in android.hardware.tv.cec.V1_0.SendMessageResult,
-// offset by 10.
-enum SendMessageResult {
-    SEND_MESSAGE_RESULT_UNKNOWN = 0;
-    SUCCESS = 10;
-    NACK = 11;
-    BUSY = 12;
-    FAIL = 13;
-}
-
-// Whether a HDMI CEC message is sent from this device, to this device, or neither.
-enum MessageDirection {
-    MESSAGE_DIRECTION_UNKNOWN = 0;
-    MESSAGE_DIRECTION_OTHER = 1;    // None of the other options.
-    OUTGOING = 2;                   // Sent from this device.
-    INCOMING = 3;                   // Sent to this device.
-    TO_SELF = 4;                    // Sent from this device, to this device. Indicates a bug.
-}
-
-// User control commands. Each value can represent an individual command, or a set of commands.
-// Values correspond to "CEC Table 30 UI Command Codes" in the HDMI CEC 1.4b spec, offset by 0x100.
-enum UserControlPressedCommand {
-    USER_CONTROL_PRESSED_COMMAND_UNKNOWN = 0;
-
-    // Represents all codes that are not represented by another value.
-    USER_CONTROL_PRESSED_COMMAND_OTHER = 1;
-
-    // Represents all number codes (codes 0x1E through 0x29).
-    NUMBER = 2;
-
-    // Navigation
-    SELECT = 0x100;
-    UP = 0x101;
-    DOWN = 0x102;
-    LEFT = 0x103;
-    RIGHT = 0x104;
-    RIGHT_UP = 0x105;
-    RIGHT_DOWN = 0x106;
-    LEFT_UP = 0x107;
-    LEFT_DOWN = 0x108;
-    EXIT = 0x10D;
-
-    // Volume
-    VOLUME_UP = 0x141;
-    VOLUME_DOWN = 0x142;
-    VOLUME_MUTE = 0x143;
-
-    // Power
-    POWER = 0x140;
-    POWER_TOGGLE = 0x16B;
-    POWER_OFF = 0x16C;
-    POWER_ON = 0x16D;
-}
-
-// Reason parameter of the <Feature Abort> message.
-// Values correspond to "CEC Table 29 Operand Descriptions" in the HDMI CEC 1.4b spec,
-// offset by 10.
-enum FeatureAbortReason {
-    FEATURE_ABORT_REASON_UNKNOWN = 0;
-    UNRECOGNIZED_OPCODE = 10;
-    NOT_IN_CORRECT_MODE_TO_RESPOND = 11;
-    CANNOT_PROVIDE_SOURCE = 12;
-    INVALID_OPERAND = 13;
-    REFUSED = 14;
-    UNABLE_TO_DETERMINE = 15;
-}
\ No newline at end of file
diff --git a/core/proto/android/stats/intelligence/enums.proto b/core/proto/android/stats/intelligence/enums.proto
deleted file mode 100644
index 0c210e3..0000000
--- a/core/proto/android/stats/intelligence/enums.proto
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.intelligence;
-option java_outer_classname = "IntelligenceStatsEnums";
-
-enum Status {
-  // The value wasn't set.
-  // protoc requires enum values to be unique by package rather than enum type.
-  // This forces us to prefix the enum values.
-  STATUS_UNKNOWN = 0;
-  // The event succeeded.
-  STATUS_SUCCEEDED = 1;
-  // The event had an error.
-  STATUS_FAILED = 2;
-}
-
-enum EventType {
-  // The value wasn't set.
-  EVENT_UNKNOWN = 0;
-  // ContentSuggestionsService classifyContentSelections call.
-  EVENT_CONTENT_SUGGESTIONS_CLASSIFY_CONTENT_CALL = 1;
-  // ContentSuggestionsService suggestContentSelections call.
-  EVENT_CONTENT_SUGGESTIONS_SUGGEST_CONTENT_CALL = 2;
-}
diff --git a/core/proto/android/stats/launcher/Android.bp b/core/proto/android/stats/launcher/Android.bp
deleted file mode 100644
index 976a0b8..0000000
--- a/core/proto/android/stats/launcher/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library {
-    name: "launcherprotosnano",
-    proto: {
-        type: "nano",
-        output_params: ["store_unknown_fields=true"],
-        include_dirs: ["external/protobuf/src"],
-    },
-
-    sdk_version: "current",
-    srcs: [
-        "*.proto",
-    ],
-}
-
-java_library {
-    name: "launcherprotoslite",
-    proto: {
-        type: "lite",
-        include_dirs: ["external/protobuf/src"],
-    },
-
-    sdk_version: "current",
-    srcs: [
-        "*.proto",
-    ],
-}
diff --git a/core/proto/android/stats/launcher/launcher.proto b/core/proto/android/stats/launcher/launcher.proto
deleted file mode 100644
index fc177d5..0000000
--- a/core/proto/android/stats/launcher/launcher.proto
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.stats.launcher;
-option java_multiple_files = true;
-
-enum LauncherAction {
-    DEFAULT_ACTION = 0;
-    LAUNCH_APP = 1;
-    LAUNCH_TASK = 2;
-    DISMISS_TASK = 3;
-    LONGPRESS = 4;
-    DRAGDROP = 5;
-    SWIPE_UP = 6;
-    SWIPE_DOWN = 7;
-    SWIPE_LEFT = 8;
-    SWIPE_RIGHT = 9;
-}
-
-enum LauncherState {
-    LAUNCHER_STATE_UNSPECIFIED = 0;
-    BACKGROUND = 1;
-    HOME = 2;
-    OVERVIEW = 3;
-    ALLAPPS = 4;
-    UNCHANGED = 5;
-}
-
-message LauncherTarget {
-    enum Type {
-        NONE = 0;
-        ITEM_TYPE = 1;
-        CONTROL_TYPE = 2;
-        CONTAINER_TYPE = 3;
-    }
-    enum Item {
-        DEFAULT_ITEM = 0;
-        APP_ICON = 1;
-        SHORTCUT = 2;
-        WIDGET = 3;
-        FOLDER_ICON = 4;
-        DEEPSHORTCUT = 5;
-        SEARCHBOX = 6;
-        EDITTEXT = 7;
-        NOTIFICATION = 8;
-        TASK = 9;
-    }
-    enum Container {
-        DEFAULT_CONTAINER = 0;
-        HOTSEAT = 1;
-        FOLDER = 2;
-        PREDICTION = 3;
-        SEARCHRESULT = 4;
-    }
-    enum Control {
-        DEFAULT_CONTROL = 0;
-        MENU = 1;
-        UNINSTALL = 2;
-        REMOVE = 3;
-    }
-    optional Type type = 1;
-    optional Item item = 2;
-    optional Container container = 3;
-    optional Control control = 4;
-    optional string launch_component = 5;
-    optional int32 page_id = 6;
-    optional int32 grid_x = 7;
-    optional int32 grid_y = 8;
-}
-
-message LauncherExtension {
-    repeated LauncherTarget src_target = 1;
-    repeated LauncherTarget dst_target = 2;
-}
diff --git a/core/proto/android/stats/location/location_enums.proto b/core/proto/android/stats/location/location_enums.proto
deleted file mode 100644
index 553c01c..0000000
--- a/core/proto/android/stats/location/location_enums.proto
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.location;
-option java_outer_classname = "LocationStatsEnums";
-
-
-// APIs from LocationManagerService
-enum LocationManagerServiceApi {
-    API_UNKNOWN = 0;
-    API_REQUEST_LOCATION_UPDATES = 1;
-    API_ADD_GNSS_MEASUREMENTS_LISTENER = 2;
-    API_REGISTER_GNSS_STATUS_CALLBACK = 3;
-    API_REQUEST_GEOFENCE = 4;
-    API_SEND_EXTRA_COMMAND = 5;
-}
-
-enum UsageState {
-    USAGE_STARTED = 0;
-    USAGE_ENDED = 1;
-}
-
-// Type of location providers
-enum ProviderType {
-    PROVIDER_UNKNOWN = 0;
-    PROVIDER_NETWORK = 1;
-    PROVIDER_GPS = 2;
-    PROVIDER_PASSIVE = 3;
-    PROVIDER_FUSED = 4;
-}
-
-// Type of Callback passed in for this API
-enum CallbackType {
-    CALLBACK_UNKNOWN = 0;
-    // Current API does not need a callback, e.g. sendExtraCommand
-    CALLBACK_NOT_APPLICABLE = 1;
-    CALLBACK_LISTENER = 2;
-    CALLBACK_PENDING_INTENT = 3;
-}
-
-// Possible values for mQuality field in
-// frameworks/base/location/java/android/location/LocationRequest.java
-enum LocationRequestQuality {
-    QUALITY_UNKNOWN = 0;
-    ACCURACY_FINE = 100;
-    ACCURACY_BLOCK = 102;
-    ACCURACY_CITY = 104;
-    POWER_NONE = 200;
-    POWER_LOW = 201;
-    POWER_HIGH = 203;
-}
-
-// Bucketized values for interval field in
-// frameworks/base/location/java/android/location/LocationRequest.java
-enum LocationRequestIntervalBucket {
-    INTERVAL_UNKNOWN = 0;
-    INTERVAL_BETWEEN_0_SEC_AND_1_SEC = 1;
-    INTERVAL_BETWEEN_1_SEC_AND_5_SEC = 2;
-    INTERVAL_BETWEEN_5_SEC_AND_1_MIN = 3;
-    INTERVAL_BETWEEN_1_MIN_AND_10_MIN = 4;
-    INTERVAL_BETWEEN_10_MIN_AND_1_HOUR = 5;
-    INTERVAL_LARGER_THAN_1_HOUR = 6;
-}
-
-// Bucketized values for small displacement field in
-// frameworks/base/location/java/android/location/LocationRequest.java
-// Value in meters.
-enum SmallestDisplacementBucket {
-    DISTANCE_UNKNOWN = 0;
-    DISTANCE_ZERO = 1;
-    DISTANCE_BETWEEN_0_AND_100 = 2;
-    DISTANCE_LARGER_THAN_100 = 3;
-}
-
-// Bucketized values for expire_in field in
-// frameworks/base/location/java/android/location/LocationRequest.java
-enum ExpirationBucket {
-    EXPIRATION_UNKNOWN = 0;
-    EXPIRATION_BETWEEN_0_AND_20_SEC = 1;
-    EXPIRATION_BETWEEN_20_SEC_AND_1_MIN = 2;
-    EXPIRATION_BETWEEN_1_MIN_AND_10_MIN = 3;
-    EXPIRATION_BETWEEN_10_MIN_AND_1_HOUR = 4;
-    EXPIRATION_LARGER_THAN_1_HOUR = 5;
-    EXPIRATION_NO_EXPIRY = 6;
-}
-
-// Bucketized values for radius field in
-// frameworks/base/location/java/android/location/Geofence.java
-// Value in meters.
-enum GeofenceRadiusBucket {
-    RADIUS_UNKNOWN = 0;
-    RADIUS_BETWEEN_0_AND_100 = 1;
-    RADIUS_BETWEEN_100_AND_200 = 2;
-    RADIUS_BETWEEN_200_AND_300 = 3;
-    RADIUS_BETWEEN_300_AND_1000 = 4;
-    RADIUS_BETWEEN_1000_AND_10000 = 5;
-    RADIUS_LARGER_THAN_100000 = 6;
-    RADIUS_NEGATIVE = 7;
-}
-
-// Caller Activity Importance.
-enum ActivityImportance {
-    IMPORTANCE_UNKNOWN = 0;
-    IMPORTANCE_TOP = 1;
-    IMPORTANCE_FORGROUND_SERVICE = 2;
-    IMPORTANCE_BACKGROUND = 3;
-}
diff --git a/core/proto/android/stats/mediametrics/mediametrics.proto b/core/proto/android/stats/mediametrics/mediametrics.proto
deleted file mode 100644
index eb8a3b1..0000000
--- a/core/proto/android/stats/mediametrics/mediametrics.proto
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.mediametrics;
-
-/**
- * Track how we arbitrate between microphone/input requests.
- * Logged from
- *   frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiopolicy.cpp
- * Next Tag: 10
- */
-message AudioPolicyData {
-    optional int32 status = 1;
-    optional string request_source = 2;
-    optional string request_package = 3;
-    optional int32 request_session = 4;
-    optional string request_device = 5;
-    optional string active_source = 6;
-    optional string active_package = 7;
-    optional int32 active_session = 8;
-    optional string active_device = 9;
-}
-
-/**
- * Track properties of audio recording
- * Logged from
- *   frameworks/av/media/libaudioclient/AudioRecord.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiorecord.cpp
- * Next Tag: 16
- */
-message AudioRecordData {
-    optional string encoding = 1;
-    optional string source = 2;
-    optional int32 latency = 3;
-    optional int32 samplerate = 4;
-    optional int32 channels = 5;
-    optional int64 created_millis = 6;
-    optional int64 duration_millis = 7;
-    optional int32 count = 8;
-    optional int32 error_code = 9;
-    optional string error_function = 10;
-    optional int32 port_id = 11;
-    optional int32 frame_count = 12;
-    optional string attributes = 13;
-    optional int64 channel_mask = 14;
-    optional int64 start_count = 15;
-
-}
-
-/**
- * Track audio thread performance data
- * Logged from
- *   frameworks/av/media/libnblog/ReportPerformance.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiothread.cpp
- * Next Tag: 28
- */
-message AudioThreadData {
-    optional string type = 1;
-    optional int32 framecount = 2;
-    optional int32 samplerate = 3;
-    optional string work_millis_hist = 4;
-    optional string latency_millis_hist = 5;
-    optional string warmup_millis_hist = 6;
-    optional int64 underruns = 7;
-    optional int64 overruns = 8;
-    optional int64 active_millis = 9;
-    optional int64 duration_millis = 10;
-
-    optional int32 id = 11;
-    optional int32 port_id = 12;
-    optional int32 sample_rate = 13;
-    optional int64 channel_mask = 14;
-    optional string encoding = 15;
-    optional int32 frame_count = 16;
-    optional string output_device = 17;
-    optional string input_device = 18;
-    optional double io_jitter_mean_millis = 19;
-    optional double io_jitter_stddev_millis = 20;
-    optional double process_time_mean_millis = 21;
-    optional double process_time_stddev_millis = 22;
-    optional double timestamp_jitter_mean_millis = 23;
-    optional double timestamp_jitter_stddev_millis = 24;
-    optional double latency_mean_millis = 25;
-    optional double latency_stddev_millis = 26;
-
-}
-
-/**
- * Track audio track playback data
- * Logged from
- *   frameworks/av/media/libaudioclient/AudioTrack.cpp
- *   frameworks/av/services/mediaanalytics/statsd_audiotrack.cpp
- * Next Tag: 12
- */
-message AudioTrackData {
-    optional string stream_type = 1;
-    optional string content_type = 2;
-    optional string track_usage = 3;
-    optional int32 sample_rate = 4;
-    optional int64 channel_mask = 5;
-
-    optional int32 underrun_frames = 6;
-    optional int32 startup_glitch = 7;
-
-    optional int32 port_id = 8;
-    optional string encoding = 9;
-    optional int32 frame_count = 10;
-    optional string attributes = 11;
-
-
-}
-
-/**
- * Track Media Codec usage
- * Logged from:
- *   frameworks/av/media/libstagefright/MediaCodec.cpp
- *   frameworks/av/services/mediaanalytics/statsd_codec.cpp
- * Next Tag: 26
- */
-message CodecData {
-    optional string codec = 1;
-    optional string mime = 2;
-    optional string mode = 3;
-    optional int32 encoder = 4;
-    optional int32 secure = 5;
-    optional int32 width = 6;
-    optional int32 height = 7;
-    optional int32 rotation = 8;
-    optional int32 crypto = 9;
-    optional int32 profile = 10;
-    optional int32 level = 11;
-    optional int32 max_width = 12;
-    optional int32 max_height = 13;
-    optional int32 error_code = 14;
-    optional string error_state = 15;
-    optional int64 latency_max = 16;
-    optional int64 latency_min = 17;
-    optional int64 latency_avg = 18;
-    optional int64 latency_count = 19;
-    optional int64 latency_unknown = 20;
-    optional int32 queue_input_buffer_error = 21;
-    optional int32 queue_secure_input_buffer_error = 22;
-    optional string bitrate_mode = 23;
-    optional int32 bitrate = 24;
-    optional int64 lifetime_millis = 25;
-}
-
-/**
- * Track Media Extractor (pulling video/audio streams out of containers) usage
- * Logged from:
- *   frameworks/av/media/libstagefright/RemoteMediaExtractor.cpp
- *   frameworks/av/services/mediaanalytics/statsd_extractor.cpp
- * Next Tag: 5
- */
-message ExtractorData {
-    optional string format = 1;
-    optional string mime = 2;
-    optional int32 tracks = 3;
-
-    enum EntryPoint {
-        UNSET = 0; // For backwards compatibility with clients that don't
-                   // collect the entry point.
-        SDK = 1;
-        NDK_WITH_JVM = 2;
-        NDK_NO_JVM = 3;
-        OTHER = 4; // For extractor users that don't make use of the APIs.
-    }
-
-    optional EntryPoint entry_point = 4 [default = UNSET];
-}
-
-/**
- * Track Media Player usage
- * this handles both nuplayer and nuplayer2
- * Logged from:
- *   frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
- *   frameworks/av/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
- *   frameworks/av/services/mediaanalytics/statsd_nuplayer.cpp
- * Next Tag: 21
- */
-message NuPlayerData {
-    optional string whichPlayer = 1;
-
-    optional string video_mime = 2;
-    optional string video_codec = 3;
-    optional int32 width = 4;
-    optional int32 height = 5;
-    optional int64 frames = 6;
-    optional int64 frames_dropped = 7;
-    optional double framerate = 8;
-    optional string audio_mime = 9;
-    optional string audio_codec = 10;
-    optional int64 duration_millis = 11;
-    optional int64 playing_millis = 12;
-    optional int32 error = 13;
-    optional int32 error_code = 14;
-    optional string error_state = 15;
-    optional string data_source_type = 16;
-    optional int64 rebuffering_millis = 17;
-    optional int32 rebuffers = 18;
-    optional int32 rebuffer_at_exit = 19;
-    optional int64 frames_dropped_startup = 20;
-}
-
-/**
- * Track information about recordings (e.g. camcorder)
- * Logged from
- *   frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
- *   frameworks/av/services/mediaanalytics/if_statsd.cpp
- * Next Tag: 22
- */
-message RecorderData {
-    optional string audio_mime = 1;
-    optional string video_mime = 2;
-    optional int32 video_profile = 3;
-    optional int32 video_level = 4;
-    optional int32 width = 5;
-    optional int32 height = 6;
-    optional int32 rotation = 7;
-    optional int32 framerate = 8;
-    optional int32 capture_fps = 9;
-    optional double capture_fps_enable = 10;
-    optional int64 duration_millis = 11;
-    optional int64 paused_millis = 12;
-    optional int32 paused_count = 13;
-    optional int32 audio_bitrate = 14;
-    optional int32 audio_channels = 15;
-    optional int32 audio_samplerate = 16;
-    optional int32 movie_timescale = 17;
-    optional int32 audio_timescale = 18;
-    optional int32 video_timescale = 19;
-    optional int32 video_bitrate = 20;
-    optional int32 iframe_interval = 21;
-}
-
-enum StreamType {
-    STREAM_TYPE_UNKNOWN = 0;
-    STREAM_TYPE_OTHER = 1;
-    STREAM_TYPE_PROGRESSIVE = 2;
-    STREAM_TYPE_DASH = 3;
-    STREAM_TYPE_HLS = 4;
-    STREAM_TYPE_SS = 5;
-}
-
-enum DrmType {
-    DRM_TYPE_NONE = 0;
-    DRM_TYPE_OTHER = 1;
-    DRM_TYPE_PLAY_READY = 2;
-    DRM_TYPE_WV_L1 = 3;
-    DRM_TYPE_WV_L3 = 4;
-}
-
-enum PlaybackType {
-    PLAYBACK_TYPE_VOD = 0;
-    PLAYBACK_TYPE_LIVE = 1;
-    PLAYBACK_TYPE_OTHER = 2;
-}
-
-enum ContentType {
-    CONTENT_TYPE_MAIN = 0;
-    CONTENT_TYPE_AD = 1;
-    CONTENT_TYPE_OTHER = 2;
-}
-
-enum StreamSourceType {
-    STREAM_SOURCE_UNKNOWN = 0;
-    STREAM_SOURCE_NETWORK = 1;
-    STREAM_SOURCE_DEVICE = 2;
-    STREAM_SOURCE_MIXED = 3;
-}
-enum NetworkType {
-    NETWORK_TYPE_NONE = 0;
-    NETWORK_TYPE_OTHER = 1;
-    NETWORK_TYPE_WIFI = 2;
-    NETWORK_TYPE_ETHERNET = 3;
-    NETWORK_TYPE_2G = 4;
-    NETWORK_TYPE_3G = 5;
-    NETWORK_TYPE_4G = 6;
-    NETWORK_TYPE_5G_NSA = 7;
-    NETWORK_TYPE_5G_SA = 8;
-}
-
-enum PlaybackState {
-    // Playback has not started (initial state)
-    NOT_STARTED = 0;
-    // Playback is buffering in the background for initial playback start
-    JOINING_BACKGROUND = 1;
-    // Playback is buffering in the foreground for initial playback start
-    JOINING_FOREGROUND = 2;
-    // Playback is actively playing
-    PLAYING = 3;
-    // Playback is paused but ready to play
-    PAUSED = 4;
-    // Playback is handling a seek
-    SEEKING = 5;
-    // Playback is buffering to resume active playback
-    BUFFERING = 6;
-    // Playback is buffering while paused
-    PAUSED_BUFFERING = 7;
-    // Playback is suppressed (e.g. due to audio focus loss)
-    SUPPRESSED = 8;
-    // Playback is suppressed (e.g. due to audio focus loss) while buffering to resume a
-    // playback
-    SUPPRESSED_BUFFERING = 9;
-    // Playback has reached the end of the media
-    ENDED = 10;
-    // Playback is stopped and can be restarted
-    STOPPED = 11;
-    // Playback is stopped due a fatal error and can be retried
-    FAILED = 12;
-    // Playback is interrupted by an ad
-    INTERRUPTED_BY_AD = 13;
-    // Playback is abandoned before reaching the end of the media
-    ABANDONED = 14;
-}
-
-enum PlaybackErrorCode {
-    ERROR_CODE_UNKNOWN = 0;
-    ERROR_CODE_OTHER = 1;
-    ERROR_CODE_RUNTIME = 2;
-}
-
-enum TrackType {
-    AUDIO = 0;
-    VIDEO = 1;
-    TEXT = 2;
-}
-enum TrackState {
-    OFF = 0;
-    ON = 1;
-}
-enum TrackChangeReason {
-    REASON_UNKNOWN = 0;
-    REASON_OTHER = 1;
-    REASON_INITIAL = 2;
-    REASON_MANUAL = 3;
-    REASON_ADAPTIVE = 4;
-}
diff --git a/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto b/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto
deleted file mode 100644
index 138782b..0000000
--- a/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.stats.mediaprovider;
-option java_multiple_files = true;
-
-enum VolumeType {
-    // Volume is unknown
-    UNKNOWN = 0;
-    // Volume is MediaStore.VOLUME_INTERNAL
-    INTERNAL = 1;
-    // Volume is MediaStore.VOLUME_EXTERNAL_PRIMARY
-    EXTERNAL_PRIMARY = 2;
-    // Volume is non-primary external storage
-    EXTERNAL_OTHER = 3;
-}
diff --git a/core/proto/android/stats/otaupdate/updateengine_enums.proto b/core/proto/android/stats/otaupdate/updateengine_enums.proto
deleted file mode 100644
index a6e9919..0000000
--- a/core/proto/android/stats/otaupdate/updateengine_enums.proto
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.stats.otaupdate;
-
-// The payload type of an OTA update attempt on A/B devices.
-enum PayloadType {
-    FULL = 10000;
-    DELTA = 10001;
-}
-
-// The attempt result reported by the update engine for an OTA update.
-enum AttemptResult {
-    UPDATE_SUCCEEDED = 10000;
-    INTERNAL_ERROR = 10001;
-    PAYLOAD_DOWNLOAD_ERROR = 10002;
-    METADATA_MALFORMED = 10003;
-    OPERATION_MALFORMED = 10004;
-    OPERATION_EXECUTION_ERROR = 10005;
-    METADATA_VERIFICATION_FAILED = 10006;
-    PAYLOAD_VERIFICATION_FAILED = 10007;
-    VERIFICATION_FAILED = 10008;
-    POSTINSTALL_FAILED = 10009;
-    ABNORMAL_TERMINATION = 10010;
-    UPDATE_CANCELED = 10011;
-    UPDATE_SUCCEEDED_NOT_ACTIVE = 10012;
-}
-
-// The error code reported by the update engine after an OTA update attempt
-// on A/B devices. More details in system/update_engine/common/error_code.h
-enum ErrorCode {
-    SUCCESS = 10000;
-    ERROR = 10001;
-    FILESYSTEM_COPIER_ERROR = 10004;
-    POST_INSTALL_RUNNER_ERROR = 10005;
-    PAYLOAD_MISMATCHED_TYPE_ERROR = 10006;
-    INSTALL_DEVICE_OPEN_ERROR = 10007;
-    KERNEL_DEVICE_OPEN_ERROR = 10008;
-    DOWNLOAD_TRANSFER_ERROR = 10009;
-    PAYLOAD_HASH_MISMATCH_ERROR = 10010;
-    PAYLOAD_SIZE_MISMATCH_ERROR = 10011;
-    DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 10012;
-    DOWNLOAD_NEW_PARTITION_INFO_ERROR = 10013;
-    DOWNLOAD_WRITE_ERROR = 10014;
-    NEW_ROOTFS_VERIFICATION_ERROR = 10015;
-    SIGNED_DELTA_PAYLOAD_EXPECTED_ERROR = 10017;
-    DOWNLOAD_PAYLOAD_PUB_KEY_VERIFICATION_ERROR = 10018;
-    DOWNLOAD_STATE_INITIALIZATION_ERROR = 10020;
-    DOWNLOAD_INVALID_METADATA_MAGIC_STRING = 10021;
-    DOWNLOAD_SIGNATURE_MISSING_IN_MANIFEST = 10022;
-    DOWNLOAD_MANIFEST_PARSE_ERROR = 10023;
-    DOWNLOAD_METADATA_SIGNATURE_ERROR = 10024;
-    DOWNLOAD_METADATA_SIGNATURE_VERIFICATION_ERROR = 10025;
-    DOWNLOAD_METADATA_SIGNATURE_MISMATCH = 10026;
-    DOWNLOAD_OPERATION_HASH_VERIFICATION_ERROR = 10027;
-    DOWNLOAD_OPERATION_EXECUTION_ERROR = 10028;
-    DOWNLOAD_OPERATION_HASH_MISMATCH = 10029;
-    DOWNLOAD_INVALID_METADATA_SIZE = 10032;
-    DOWNLOAD_INVALID_METADATA_SIGNATURE = 10033;
-    DOWNLOAD_OPERATION_HASH_MISSING_ERROR = 10038;
-    DOWNLOAD_METADATA_SIGNATURE_MISSING_ERROR = 10039;
-    UNSUPPORTED_MAJOR_PAYLOAD_VERSION = 10044;
-    UNSUPPORTED_MINOR_PAYLOAD_VERSION = 10045;
-    FILESYSTEM_VERIFIER_ERROR = 10047;
-    USER_CANCELED = 10048;
-    PAYLOAD_TIMESTAMP_ERROR = 10051;
-    UPDATED_BUT_NOT_ACTIVE = 10052;
-}
diff --git a/core/proto/android/stats/storage/storage_enums.proto b/core/proto/android/stats/storage/storage_enums.proto
deleted file mode 100644
index 6892e28..0000000
--- a/core/proto/android/stats/storage/storage_enums.proto
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.storage;
-
-enum ExternalStorageType {
-  UNKNOWN = 0;
-  SD_CARD = 1;
-  USB = 2;
-  OTHER = 3;
-}
diff --git a/core/proto/android/stats/style/Android.bp b/core/proto/android/stats/style/Android.bp
deleted file mode 100644
index f085a52..0000000
--- a/core/proto/android/stats/style/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library {
-    name: "styleprotosnano",
-    proto: {
-        type: "nano",
-        output_params: ["store_unknown_fields=true"],
-        include_dirs: ["external/protobuf/src"],
-    },
-
-    sdk_version: "current",
-    srcs: [
-        "*.proto",
-    ],
-}
diff --git a/core/proto/android/stats/style/style_enums.proto b/core/proto/android/stats/style/style_enums.proto
deleted file mode 100644
index 2876882..0000000
--- a/core/proto/android/stats/style/style_enums.proto
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.stats.style;
-option java_multiple_files = true;
-
-enum Action {
-    DEFAULT_ACTION = 0;
-    ONRESUME = 1;
-    ONSTOP = 2;
-    PICKER_SELECT = 3;
-    PICKER_APPLIED = 4;
-    WALLPAPER_OPEN_CATEGORY = 5;
-    WALLPAPER_SELECT = 6;
-    WALLPAPER_APPLIED = 7;
-    WALLPAPER_EXPLORE = 8;
-    WALLPAPER_DOWNLOAD = 9;
-    WALLPAPER_REMOVE = 10;
-    LIVE_WALLPAPER_DOWNLOAD_SUCCESS = 11;
-    LIVE_WALLPAPER_DOWNLOAD_FAILED = 12;
-    LIVE_WALLPAPER_DOWNLOAD_CANCELLED = 13;
-    LIVE_WALLPAPER_DELETE_SUCCESS = 14;
-    LIVE_WALLPAPER_DELETE_FAILED = 15;
-    LIVE_WALLPAPER_APPLIED = 16;
-    LIVE_WALLPAPER_INFO_SELECT = 17;
-    LIVE_WALLPAPER_CUSTOMIZE_SELECT = 18;
-    LIVE_WALLPAPER_QUESTIONNAIRE_SELECT = 19;
-    LIVE_WALLPAPER_QUESTIONNAIRE_APPLIED = 20;
-    LIVE_WALLPAPER_EFFECT_SHOW = 21;
-    APP_LAUNCHED = 22;
-}
-
-enum LocationPreference {
-    LOCATION_PREFERENCE_UNSPECIFIED = 0;
-    LOCATION_UNAVAILABLE = 1;
-    LOCATION_CURRENT = 2;
-    LOCATION_MANUAL = 3;
-}
-
-enum DatePreference {
-    DATE_PREFERENCE_UNSPECIFIED = 0;
-    DATE_UNAVAILABLE = 1;
-    DATE_MANUAL = 2;
-}
-
-enum LaunchedPreference {
-    LAUNCHED_PREFERENCE_UNSPECIFIED = 0;
-    LAUNCHED_LAUNCHER = 1;
-    LAUNCHED_SETTINGS = 2;
-    LAUNCHED_SUW = 3;
-    LAUNCHED_TIPS = 4;
-    LAUNCHED_LAUNCH_ICON = 5;
-    LAUNCHED_CROP_AND_SET_ACTION = 6;
-    LAUNCHED_DEEP_LINK = 7;
-}
diff --git a/core/proto/android/stats/sysui/notification_enums.proto b/core/proto/android/stats/sysui/notification_enums.proto
deleted file mode 100644
index 30bdeca..0000000
--- a/core/proto/android/stats/sysui/notification_enums.proto
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.sysui;
-
-// Enum used in NotificationReported and NotificationChannelModified atoms
-enum NotificationImportance {  // Constants from NotificationManager.java
-  IMPORTANCE_UNSPECIFIED = -1000;  // Should not occur for real notifications.
-  IMPORTANCE_NONE = 0;  // No importance: does not show in the shade.
-  IMPORTANCE_MIN = 1;  // Minimum to show in the shade.
-  IMPORTANCE_LOW = 2;  // Shows in shade, maybe status bar, no buzz/beep.
-  IMPORTANCE_DEFAULT = 3;  // Shows everywhere, makes noise, no heads-up.
-  IMPORTANCE_HIGH = 4;  // Shows everywhere, makes noise, heads-up, may full-screen.
-  IMPORTANCE_IMPORTANT_CONVERSATION = 5;  // High + isImportantConversation().
-}
diff --git a/core/proto/android/stats/textclassifier/Android.bp b/core/proto/android/stats/textclassifier/Android.bp
deleted file mode 100644
index bf90227..0000000
--- a/core/proto/android/stats/textclassifier/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library_static {
-    name: "textclassifierprotoslite",
-    proto: {
-        type: "lite",
-    },
-    srcs: [
-        "*.proto",
-    ],
-}
\ No newline at end of file
diff --git a/core/proto/android/stats/textclassifier/textclassifier_enums.proto b/core/proto/android/stats/textclassifier/textclassifier_enums.proto
deleted file mode 100644
index 4be7b7c..0000000
--- a/core/proto/android/stats/textclassifier/textclassifier_enums.proto
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.stats.textclassifier;
-option java_multiple_files = true;
-
-enum EventType {
-    TYPE_UNKNOWN = 0;
-    // User started a new selection.
-    SELECTION_STARTED = 1;
-    // User modified an existing selection.
-    SELECTION_MODIFIED = 2;
-    // Smart selection triggered for a single token (word).
-    SMART_SELECTION_SINGLE = 3;
-    // Smart selection triggered spanning multiple tokens (words).
-    SMART_SELECTION_MULTI = 4;
-    // Something else other than user or the default TextClassifier triggered a selection.
-    AUTO_SELECTION = 5;
-    // Smart actions shown to the user.
-    ACTIONS_SHOWN = 6;
-    // User clicked a link.
-    LINK_CLICKED = 7;
-    // User typed over the selection.
-    OVERTYPE = 8;
-    // User clicked on Copy action.
-    COPY_ACTION = 9;
-    // User clicked on Paste action.
-    PASTE_ACTION = 10;
-    // User clicked on Cut action.
-    CUT_ACTION = 11;
-    // User clicked on Share action.
-    SHARE_ACTION = 12;
-    // User clicked on a Smart action.
-    SMART_ACTION = 13;
-    // User dragged+dropped the selection.
-    SELECTION_DRAG = 14;
-    // Selection is destroyed.
-    SELECTION_DESTROYED = 15;
-    // User clicked on a custom action.
-    OTHER_ACTION = 16;
-    // User clicked on Select All action
-    SELECT_ALL = 17;
-    // User reset the smart selection.
-    SELECTION_RESET = 18;
-    // User composed a reply.
-    MANUAL_REPLY = 19;
-    // TextClassifier generated some actions
-    ACTIONS_GENERATED = 20;
-    // Some text links were generated
-    LINKS_GENERATED = 21;
-}
-
-enum WidgetType {
-    WIDGET_TYPE_UNKNOWN = 0;
-    // Standard TextView
-    WIDGET_TYPE_TEXTVIEW = 1;
-    // EditText
-    WIDGET_TYPE_EDITTEXT = 2;
-    // Not selectable textview
-    WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = 3;
-    // Standard Webview
-    WIDGET_TYPE_WEBVIEW = 4;
-    // Editable TextView
-    WIDGET_TYPE_EDIT_WEBVIEW = 5;
-    // Custom text widget
-    WIDGET_TYPE_CUSTOM_TEXTVIEW = 6;
-    // Custom editable text widget.
-    WIDGET_TYPE_CUSTOM_EDITTEXT = 7;
-    // Non-selectable text widget.
-    WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = 8;
-    // Notification
-    WIDGET_TYPE_NOTIFICATION = 9;
-}
diff --git a/core/proto/android/stats/tls/enums.proto b/core/proto/android/stats/tls/enums.proto
deleted file mode 100644
index a64137d..0000000
--- a/core/proto/android/stats/tls/enums.proto
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-syntax = "proto2";
-package android.stats.tls;
-
-// Keep in sync with
-// external/conscrypt/{android,platform}/src/main/java/org/conscrypt/Platform.java
-enum Protocol {
-    UNKNOWN_PROTO = 0;
-    SSL_V3 = 1;
-    TLS_V1 = 2;
-    TLS_V1_1 = 3;
-    TLS_V1_2 = 4;
-    TLS_V1_3 = 5;
-}
-
-// Cipher suites' ids are based on IANA's database:
-// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
-//
-// If you add new cipher suite, make sure id is the same as in  IANA's database (see link above)
-//
-// Keep in sync with
-// external/conscrypt/{android,platform}/src/main/java/org/conscrypt/Platform.java
-enum CipherSuite {
-    UNKNOWN_CIPHER_SUITE = 0x0000;
-
-    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A;
-    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014;
-    TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035;
-    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009;
-    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013;
-    TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F;
-    TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A;
-
-    // TLSv1.2 cipher suites
-    TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C;
-    TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D;
-    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F;
-    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030;
-    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B;
-    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C;
-    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9;
-    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8;
-
-    // Pre-Shared Key (PSK) cipher suites
-    TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C;
-    TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D;
-    TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035;
-    TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036;
-    TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAC;
-
-    // TLS 1.3 cipher suites
-    TLS_AES_128_GCM_SHA256 = 0x1301;
-    TLS_AES_256_GCM_SHA384 = 0x1302;
-    TLS_CHACHA20_POLY1305_SHA256 = 0x1303;
-}
-
diff --git a/core/proto/android/stats/tv/tif_enums.proto b/core/proto/android/stats/tv/tif_enums.proto
deleted file mode 100644
index a9028e5..0000000
--- a/core/proto/android/stats/tv/tif_enums.proto
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.stats.tv;
-option java_multiple_files = true;
-
-// Enums for TV Input Framework
-option java_outer_classname = "TifStatsEnums";
-
-// Tune State of a TV Input Service Framework
-enum TifTuneState {
-  TIF_TUNE_STATE_UNKNOWN = 0;
-  CREATED = 1;
-  SURFACE_ATTACHED = 2;
-  SURFACE_DETACHED = 3;
-  RELEASED = 4;
-  TUNE_STARTED = 5;
-  VIDEO_AVAILABLE = 6;
-
-  // Keep in sync with TvInputManager
-  // Use the TvInputManager value + 100
-  VIDEO_UNAVAILABLE_REASON_UNKNOWN = 100;
-  VIDEO_UNAVAILABLE_REASON_TUNING = 101;
-  VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 102;
-  VIDEO_UNAVAILABLE_REASON_BUFFERING = 103;
-  VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 104;
-  VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = 105;
-  VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE = 106;
-  VIDEO_UNAVAILABLE_REASON_CAS_INSUFFICIENT_OUTPUT_PROTECTION=107;
-  VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED=108;
-  VIDEO_UNAVAILABLE_REASON_CAS_NO_LICENSE=109;
-  VIDEO_UNAVAILABLE_REASON_CAS_LICENSE_EXPIRED=110;
-  VIDEO_UNAVAILABLE_REASON_CAS_NEED_ACTIVATION=111;
-  VIDEO_UNAVAILABLE_REASON_CAS_NEED_PAIRING=112;
-  VIDEO_UNAVAILABLE_REASON_CAS_NO_CARD=113;
-  VIDEO_UNAVAILABLE_REASON_CAS_CARD_MUTE=114;
-  VIDEO_UNAVAILABLE_REASON_CAS_CARD_INVALID=115;
-  VIDEO_UNAVAILABLE_REASON_CAS_BLACKOUT=116;
-  VIDEO_UNAVAILABLE_REASON_CAS_REBOOTING=117;
-  VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN=118;
-}
diff --git a/core/proto/android/telecomm/enums.proto b/core/proto/android/telecomm/enums.proto
deleted file mode 100644
index 5ca4a85..0000000
--- a/core/proto/android/telecomm/enums.proto
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.telecom;
-
-option java_outer_classname = "TelecomProtoEnums";
-option java_multiple_files = true;
-
-/**
- * Call states, primarily used in CallState.java,
- * Call.java, and CallsManager.java in packages/services.
- */
-enum CallStateEnum {
-    /**
-     * Indicates that a call is new and not connected. This is used as the default state internally
-     * within Telecom and should not be used between Telecom and call services. Call services are
-     * not expected to ever interact with NEW calls, but {@link android.telecom.InCallService}s will
-     * see calls in this state.
-     */
-    NEW = 0;
-
-    /**
-     * The initial state of an outgoing {@code Call}.
-     * Common transitions are to {@link #DIALING} state for a successful call or
-     * {@link #DISCONNECTED} if it failed.
-     */
-    CONNECTING = 1;
-
-    /**
-     * The state of an outgoing {@code Call} when waiting on user to select a
-     * {@link android.telecom.PhoneAccount} through which to place the call.
-     */
-    SELECT_PHONE_ACCOUNT = 2;
-
-    /**
-     * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
-     * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
-     * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
-     * if the call was disconnected somehow (e.g., failure or cancellation of the call by the user).
-     */
-    DIALING = 3;
-
-    /**
-     * Indicates that a call is incoming and the user still has the option of answering, rejecting,
-     * or doing nothing with the call. This state is usually associated with some type of audible
-     * ringtone. Normal transitions are to {@link #ACTIVE} if answered or {@link #DISCONNECTED}
-     * otherwise.
-     */
-    RINGING = 4;
-
-    /**
-     * Indicates that a call is currently connected to another party and a communication channel is
-     * open between them. The normal transition to this state is by the user answering a
-     * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
-     */
-    ACTIVE = 5;
-
-    /**
-     * Indicates that the call is currently on hold. In this state, the call is not terminated
-     * but no communication is allowed until the call is no longer on hold. The typical transition
-     * to this state is by the user putting an {@link #ACTIVE} call on hold by explicitly performing
-     * an action, such as clicking the hold button.
-     */
-    ON_HOLD = 6;
-
-    /**
-     * Indicates that a call is currently disconnected. All states can transition to this state
-     * by the call service giving notice that the connection has been severed. When the user
-     * explicitly ends a call, it will not transition to this state until the call service confirms
-     * the disconnection or communication was lost to the call service currently responsible for
-     * this call (e.g., call service crashes).
-     */
-    DISCONNECTED = 7;
-
-    /**
-     * Indicates that the call was attempted (mostly in the context of outgoing, at least at the
-     * time of writing) but cancelled before it was successfully connected.
-     */
-    ABORTED = 8;
-
-    /**
-     * Indicates that the call is in the process of being disconnected and will transition next
-     * to a {@link #DISCONNECTED} state.
-     * <p>
-     * This state is not expected to be communicated from the Telephony layer, but will be reported
-     * to the InCall UI for calls where disconnection has been initiated by the user but the
-     * ConnectionService has confirmed the call as disconnected.
-     */
-    DISCONNECTING = 9;
-
-    /**
-     * Indicates that the call is in the process of being pulled to the local device.
-     * <p>
-     * This state should only be set on a call with
-     * {@link android.telecom.Connection#PROPERTY_IS_EXTERNAL_CALL} and
-     * {@link android.telecom.Connection#CAPABILITY_CAN_PULL_CALL}.
-     */
-    PULLING = 10;
-
-    /**
-     * Indicates that an incoming call has been answered by the in-call UI, but Telephony hasn't yet
-     * set the call to active.
-     */
-    ANSWERED = 11;
-
-    /**
-     * Indicates that the call is undergoing audio processing by a different app in the background.
-     * @see android.telecom.Call#STATE_AUDIO_PROCESSING
-     */
-    AUDIO_PROCESSING = 12;
-
-    /**
-     * Indicates that the call is in a fake ringing state.
-     * @see android.telecom.Call#STATE_SIMULATED_RINGING
-     */
-    SIMULATED_RINGING = 13;
-}
-
-// Disconnect causes for a call. Primarily used by android/telecom/DisconnectCause.java
-enum DisconnectCauseEnum {
-    /**
-     * Disconnected because of an unknown or unspecified reason.
-     */
-    UNKNOWN = 0;
-
-    /**
-     * Disconnected because there was an error, such as a problem with the network.
-     */
-    ERROR = 1;
-
-    /**
-     * Disconnected because of a local user-initiated action, such as hanging up.
-     */
-    LOCAL = 2;
-
-    /**
-     * Disconnected because of a remote user-initiated action, such as the other party hanging up
-     * up.
-     */
-    REMOTE = 3;
-
-    /**
-     * Disconnected because it has been canceled.
-     */
-    CANCELED = 4;
-
-    /**
-     * Disconnected because there was no response to an incoming call.
-     */
-    MISSED = 5;
-
-    /**
-     * Disconnected because the user rejected an incoming call.
-     */
-    REJECTED = 6;
-
-    /**
-     * Disconnected because the other party was busy.
-     */
-    BUSY = 7;
-
-    /**
-     * Disconnected because of a restriction on placing the call, such as dialing in airplane
-     * mode.
-     */
-    RESTRICTED = 8;
-
-    /**
-     * Disconnected for reason not described by other disconnect codes.
-     */
-    OTHER = 9;
-
-    /**
-     * Disconnected because the connection manager did not support the call. The call will be tried
-     * again without a connection manager. See {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
-     */
-    CONNECTION_MANAGER_NOT_SUPPORTED = 10;
-
-    /**
-     * Disconnected because the user did not locally answer the incoming call, but it was answered
-     * on another device where the call was ringing.
-     */
-    ANSWERED_ELSEWHERE = 11;
-
-    /**
-     * Disconnected because the call was pulled from the current device to another device.
-     */
-    CALL_PULLED = 12;
-}
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
deleted file mode 100644
index b435fe7..0000000
--- a/core/proto/android/telephony/enums.proto
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.telephony;
-
-option java_outer_classname = "TelephonyProtoEnums";
-option java_multiple_files = true;
-
-enum CallBearerEnum {
-    /** Call bearer is unknown or invalid */
-    CALL_BEARER_UNKNOWN = 0;
-
-    /** Call bearer is legacy CS */
-    CALL_BEARER_CS = 1;
-
-    /** Call bearer is IMS */
-    CALL_BEARER_IMS = 2;
-}
-
-enum CallDirectionEnum {
-    /** Call direction: unknown or invalid */
-    CALL_DIRECTION_UNKNOWN = 0;
-
-    /** Call direction: mobile originated (outgoing for this device) */
-    CALL_DIRECTION_MO = 1;
-
-    /** Call direction: mobile terminated (incoming for this device) */
-    CALL_DIRECTION_MT = 2;
-}
-
-// Call setup duration buckets.
-// See com.android.internal.telephony.metrics.VoiceCallSessionStats for definition.
-enum CallSetupDurationEnum {
-    CALL_SETUP_DURATION_UNKNOWN = 0;
-    CALL_SETUP_DURATION_EXTREMELY_FAST = 1;
-    CALL_SETUP_DURATION_ULTRA_FAST = 2;
-    CALL_SETUP_DURATION_VERY_FAST = 3;
-    CALL_SETUP_DURATION_FAST = 4;
-    CALL_SETUP_DURATION_NORMAL = 5;
-    CALL_SETUP_DURATION_SLOW = 6;
-    CALL_SETUP_DURATION_VERY_SLOW = 7;
-    CALL_SETUP_DURATION_ULTRA_SLOW = 8;
-    CALL_SETUP_DURATION_EXTREMELY_SLOW = 9;
-}
-
-// Data conn. power states, primarily used by android/telephony/DataConnectionRealTimeInfo.java.
-enum DataConnectionPowerStateEnum {
-    DATA_CONNECTION_POWER_STATE_LOW = 1;
-    DATA_CONNECTION_POWER_STATE_MEDIUM = 2;
-    DATA_CONNECTION_POWER_STATE_HIGH = 3;
-    DATA_CONNECTION_POWER_STATE_UNKNOWN = 2147483647; // Java Integer.MAX_VALUE;
-}
-
-// Network type enums, primarily used by android/telephony/TelephonyManager.java.
-// Do not add negative types.
-enum NetworkTypeEnum {
-    NETWORK_TYPE_UNKNOWN = 0;
-    NETWORK_TYPE_GPRS = 1;
-    NETWORK_TYPE_EDGE = 2;
-    NETWORK_TYPE_UMTS = 3;
-    NETWORK_TYPE_CDMA = 4;
-    NETWORK_TYPE_EVDO_0 = 5;
-    NETWORK_TYPE_EVDO_A = 6;
-    NETWORK_TYPE_1XRTT = 7;
-    NETWORK_TYPE_HSDPA = 8;
-    NETWORK_TYPE_HSUPA = 9;
-    NETWORK_TYPE_HSPA = 10;
-    NETWORK_TYPE_IDEN = 11;
-    NETWORK_TYPE_EVDO_B = 12;
-    NETWORK_TYPE_LTE = 13;
-    NETWORK_TYPE_EHRPD = 14;
-    NETWORK_TYPE_HSPAP = 15;
-    NETWORK_TYPE_GSM = 16;
-    NETWORK_TYPE_TD_SCDMA = 17;
-    NETWORK_TYPE_IWLAN = 18;
-    NETWORK_TYPE_LTE_CA = 19;
-    NETWORK_TYPE_NR = 20;
-}
-
-// Roaming type enums, see android.telephony.ServiceState.RoamingType for definitions.
-enum RoamingTypeEnum {
-    ROAMING_TYPE_NOT_ROAMING = 0;
-    ROAMING_TYPE_ROAMING = 1;
-    ROAMING_TYPE_ROAMING_DOMESTIC = 2;
-    ROAMING_TYPE_ROAMING_INTERNATIONAL = 3;
-}
-
-// Signal strength levels, as defined in android/telephony/SignalStrength.java.
-enum SignalStrengthEnum {
-    SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
-    SIGNAL_STRENGTH_POOR = 1;
-    SIGNAL_STRENGTH_MODERATE = 2;
-    SIGNAL_STRENGTH_GOOD = 3;
-    SIGNAL_STRENGTH_GREAT = 4;
-}
-
-enum ServiceStateEnum {
-    /**
-     * Normal operation condition, the phone is registered
-     * with an operator either in home network or in roaming.
-     */
-    SERVICE_STATE_IN_SERVICE = 0;
-
-    /**
-     * Phone is not registered with any operator, the phone
-     * can be currently searching a new operator to register to, or not
-     * searching to registration at all, or registration is denied, or radio
-     * signal is not available.
-     */
-    SERVICE_STATE_OUT_OF_SERVICE = 1;
-
-    /**
-     * The phone is registered and locked.  Only emergency numbers are allowed. {@more}
-     */
-    SERVICE_STATE_EMERGENCY_ONLY = 2;
-
-    /**
-     * Radio of telephony is explicitly powered off.
-     */
-    SERVICE_STATE_POWER_OFF = 3;
-}
-
-enum SimStateEnum {
-    SIM_STATE_UNKNOWN = 0;
-    /** SIM card state: no SIM card is available in the device */
-    SIM_STATE_ABSENT = 1;
-    /** SIM card state: Locked: requires the user's SIM PIN to unlock */
-    SIM_STATE_PIN_REQUIRED = 2;
-    /** SIM card state: Locked: requires the user's SIM PUK to unlock */
-    SIM_STATE_PUK_REQUIRED = 3;
-    /** SIM card state: Locked: requires a network PIN to unlock */
-    SIM_STATE_NETWORK_LOCKED = 4;
-    /** SIM card state: Ready */
-    SIM_STATE_READY = 5;
-    /** SIM card state: SIM Card is NOT READY */
-    SIM_STATE_NOT_READY = 6;
-    /** SIM card state: SIM Card Error, permanently disabled */
-    SIM_STATE_PERM_DISABLED = 7;
-    /** SIM card state: SIM Card Error, present but faulty */
-    SIM_STATE_CARD_IO_ERROR = 8;
-    /** SIM card state: SIM Card restricted, present but not usable due to
-     * carrier restrictions.
-     */
-    SIM_STATE_CARD_RESTRICTED = 9;
-    /**
-     * SIM card state: Loaded: SIM card applications have been loaded
-     * @hide
-     */
-    SIM_STATE_LOADED = 10;
-    /**
-     * SIM card state: SIM Card is present
-     * @hide
-     */
-    SIM_STATE_PRESENT = 11;
-}
-
-// Format of SMS message
-enum SmsFormatEnum {
-    /** Unknown format */
-    SMS_FORMAT_UNKNOWN = 0;
-    /** Format compliant with 3GPP TS 23.040 */
-    SMS_FORMAT_3GPP = 1;
-    /** Format compliant with 3GPP2 TS C.S0015-B */
-    SMS_FORMAT_3GPP2 = 2;
-}
-
-// Technology used to carry an SMS message
-enum SmsTechEnum {
-    /**
-     * Unknown SMS technology used to carry the SMS.
-     * This value is also used for injected SMS.
-     */
-    SMS_TECH_UNKNOWN = 0;
-    /** The SMS was carried over CS bearer in 3GPP network */
-    SMS_TECH_CS_3GPP = 1;
-    /** The SMS was carried over CS bearer in 3GPP2 network */
-    SMS_TECH_CS_3GPP2 = 2;
-    /** The SMS was carried over IMS */
-    SMS_TECH_IMS = 3;
-}
-
-// Types of SMS message
-enum SmsTypeEnum {
-    /** Normal type. */
-    SMS_TYPE_NORMAL = 0;
-    /** SMS-PP (point-to-point). */
-    SMS_TYPE_SMS_PP = 1;
-    /** Voicemail indication. */
-    SMS_TYPE_VOICEMAIL_INDICATION = 2;
-    /** Type 0 message (3GPP TS 23.040 9.2.3.9). */
-    SMS_TYPE_ZERO = 3;
-    /** WAP-PUSH message. */
-    SMS_TYPE_WAP_PUSH = 4;
-}
-
-// Incoming SMS errors
-enum SmsIncomingErrorEnum {
-    SMS_SUCCESS = 0;
-    SMS_ERROR_GENERIC = 1;
-    SMS_ERROR_NO_MEMORY = 2;
-    SMS_ERROR_NOT_SUPPORTED = 3;
-}
-
-// Outgoing SMS results
-enum SmsSendResultEnum {
-    // Unknown error
-    SMS_SEND_RESULT_UNKNOWN = 0;
-    // Success
-    SMS_SEND_RESULT_SUCCESS = 1;
-    // Permanent error
-    SMS_SEND_RESULT_ERROR = 2;
-    // Temporary error, retry
-    SMS_SEND_RESULT_ERROR_RETRY = 3;
-    // Error over IMS, retry on CS
-    SMS_SEND_RESULT_ERROR_FALLBACK = 4;
-}
-
-// Data profile of the data call. From
-// frameworks/base/telephony/java/com/android/internal/telephony/RILConstants.java
-enum DataProfileEnum {
-    DATA_PROFILE_DEFAULT = 0;
-    DATA_PROFILE_TETHERED = 1;
-    DATA_PROFILE_IMS = 2;
-    DATA_PROFILE_FOTA = 3;
-    DATA_PROFILE_CBS = 4;
-    DATA_PROFILE_OEM_BASE = 1000;
-    DATA_PROFILE_INVALID = -1;
-}
-
-// Reason of data call deactivation. From
-// frameworks/base/telephony/java/android/telephony/data/DataService.java#DeactivateDataReason
-enum DataDeactivateReasonEnum {
-    DEACTIVATE_REASON_UNKNOWN = 0;
-    DEACTIVATE_REASON_NORMAL = 1;
-    DEACTIVATE_REASON_RADIO_OFF = 2;
-    DEACTIVATE_REASON_HANDOVER = 3;
-}
-
-// IP type of the data call
-// see frameworks/base/telephony/java/android/telephony/data/ApnSetting.java#ProtocolType
-enum ApnProtocolEnum {
-    APN_PROTOCOL_IPV4 = 0;
-    APN_PROTOCOL_IPV6 = 1;
-    APN_PROTOCOL_IPV4V6 = 2;
-    APN_PROTOCOL_PPP = 3;
-}
-
-// Action taken to recover a data call that is stalled. From
-// frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
-// #RecoveryAction
-enum DataStallRecoveryActionEnum {
-    RECOVERY_ACTION_GET_DATA_CALL_LIST = 0;
-    RECOVERY_ACTION_CLEANUP = 1;
-    RECOVERY_ACTION_REREGISTER = 2;
-    RECOVERY_ACTION_RADIO_RESTART = 3;
-}
-
-// Codec quality
-enum CodecQuality {
-    /** Codec quality: unknown */
-    CODEC_QUALITY_UNKNOWN = 0;
-
-    /** Codec quality: narrowband */
-    CODEC_QUALITY_NARROWBAND = 1;
-
-    /** Codec quality: wideband */
-    CODEC_QUALITY_WIDEBAND = 2;
-
-    /** Codec quality: super-wideband */
-    CODEC_QUALITY_SUPER_WIDEBAND = 3;
-
-    /** Codec quality: fullband */
-    CODEC_QUALITY_FULLBAND = 4;
-}
diff --git a/core/proto/android/view/enums.proto b/core/proto/android/view/enums.proto
deleted file mode 100644
index a601abe..0000000
--- a/core/proto/android/view/enums.proto
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.view;
-
-option java_outer_classname = "ViewProtoEnums";
-option java_multiple_files = true;
-
-// Screen states, primarily used by android/view/Display.java.
-enum DisplayStateEnum {
-    // The display state is unknown.
-    DISPLAY_STATE_UNKNOWN = 0;
-    // The display state is off.
-    DISPLAY_STATE_OFF = 1;
-    // The display state is on.
-    DISPLAY_STATE_ON = 2;
-    // The display is dozing in a low power state; it is still on but is
-    // optimized for showing system-provided content while the device is
-    // non-interactive.
-    DISPLAY_STATE_DOZE = 3;
-    // The display is dozing in a suspended low power state; it is still on
-    // but is optimized for showing static system-provided content while the
-    // device is non-interactive.
-    DISPLAY_STATE_DOZE_SUSPEND = 4;
-    // The display is on and optimized for VR mode.
-    DISPLAY_STATE_VR = 5;
-    // The display is in a suspended full power state; it is still on but the
-    // CPU is not updating it.
-    DISPLAY_STATE_ON_SUSPEND = 6;
-}
-
-// Constants found in android.view.WindowManager.
-enum TransitionTypeEnum {
-    TRANSIT_NONE = 0;
-    TRANSIT_UNSET = -1;
-    TRANSIT_ACTIVITY_OPEN = 6;
-    TRANSIT_ACTIVITY_CLOSE = 7;
-    TRANSIT_TASK_OPEN = 8;
-    TRANSIT_TASK_CLOSE = 9;
-    TRANSIT_TASK_TO_FRONT = 10;
-    TRANSIT_TASK_TO_BACK = 11;
-    TRANSIT_WALLPAPER_CLOSE = 12;
-    TRANSIT_WALLPAPER_OPEN = 13;
-    TRANSIT_WALLPAPER_INTRA_OPEN = 14;
-    TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
-    TRANSIT_TASK_OPEN_BEHIND = 16;
-    TRANSIT_TASK_IN_PLACE = 17;
-    TRANSIT_ACTIVITY_RELAUNCH = 18;
-    TRANSIT_DOCK_TASK_FROM_RECENTS = 19 [deprecated=true];
-    TRANSIT_KEYGUARD_GOING_AWAY = 20;
-    TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
-    TRANSIT_KEYGUARD_OCCLUDE = 22;
-    TRANSIT_KEYGUARD_UNOCCLUDE = 23;
-    TRANSIT_TRANSLUCENT_ACTIVITY_OPEN = 24;
-    TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE = 25;
-    TRANSIT_CRASHING_ACTIVITY_CLOSE = 26;
-}
diff --git a/core/proto/android/view/inputmethod/inputconnection.proto b/core/proto/android/view/inputmethod/inputconnection.proto
new file mode 100644
index 0000000..ad9a95a
--- /dev/null
+++ b/core/proto/android/view/inputmethod/inputconnection.proto
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+package android.view.inputmethod;
+
+option java_multiple_files = true;
+
+/**
+ * Represents a {@link android.view.inputmethod.InputConnection} object.
+ */
+message InputConnectionProto {
+  optional string editable_text = 1 [(.android.privacy).dest = DEST_LOCAL];
+  optional string selected_text = 2 [(.android.privacy).dest = DEST_LOCAL];
+  optional int32 selected_text_start = 3;
+  optional int32 selected_text_end = 4;
+  optional int32 cursor_caps_mode = 5;
+}
\ No newline at end of file
diff --git a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
index 5c0f341..c1dce6f 100644
--- a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
+++ b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
@@ -24,6 +24,7 @@
 import "frameworks/base/core/proto/android/view/insetscontroller.proto";
 import "frameworks/base/core/proto/android/view/imeinsetssourceconsumer.proto";
 import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+import "frameworks/base/core/proto/android/view/inputmethod/inputconnection.proto";
 import "frameworks/base/core/proto/android/view/imefocuscontroller.proto";
 
 import "frameworks/base/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto";
@@ -70,6 +71,7 @@
         optional ImeInsetsSourceConsumerProto ime_insets_source_consumer = 5;
         optional EditorInfoProto editor_info = 6;
         optional ImeFocusControllerProto ime_focus_controller = 7;
+        optional InputConnectionProto input_connection = 8;
     }
 }
 
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 4bb56f8..062485d 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -35,7 +35,7 @@
     optional int32 height = 5;
     optional float horizontal_margin = 6;
     optional float vertical_margin = 7;
-    optional int32 gravity = 8;
+    optional int32 gravity = 8 [(.android.typedef) = "android.view.Gravity.GravityFlags"];
     optional int32 soft_input_mode = 9 [(.android.typedef) = "android.view.WindowManager.LayoutParams.SoftInputModeFlags"];
     optional .android.graphics.PixelFormatProto.Format format = 10;
     optional int32 window_animations = 11;
diff --git a/core/proto/android/wifi/enums.proto b/core/proto/android/wifi/enums.proto
deleted file mode 100644
index e676fef..0000000
--- a/core/proto/android/wifi/enums.proto
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.net.wifi;
-
-option java_outer_classname = "WifiProtoEnums";
-option java_multiple_files = true;
-
-/**
- * Wifi Lock modes, primarily used in
- * frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiLockManager.java.
- */
-enum WifiModeEnum {
-    /**
-     * Deprecated.
-     * Wi-Fi will be kept active, and will behave normally.
-     */
-    WIFI_MODE_FULL = 1 [deprecated=true];
-
-    /**
-     * Deprecated.
-     * Wi-Fi will be kept active, but the only operation that will be supported is initiation of
-     * scans, and the subsequent reporting of scan results.
-     */
-    WIFI_MODE_SCAN_ONLY = 2 [deprecated=true];
-
-    /**
-     * Wi-Fi will not go to power save.
-     */
-    WIFI_MODE_FULL_HIGH_PERF = 3;
-
-    /**
-     * Wi-Fi will operate with a priority to achieve low latency.
-     */
-    WIFI_MODE_FULL_LOW_LATENCY = 4;
-}
-
-/**
- * Wifi authentication type.
- */
-enum WifiAuthType {
-    AUTH_TYPE_NONE = 0;
-
-    // WPA pre-shared key.
-    AUTH_TYPE_WPA_PSK = 1;
-    // WPA using EAP authentication. Generally used with an external authentication server.
-    AUTH_TYPE_WPA_EAP = 2;
-    // IEEE 802.1X using EAP authentication and (optionally) dynamically generated WEP keys.
-    AUTH_TYPE_IEEE8021X = 3;
-    // WPA2 pre-shared key for use with soft access point.
-    AUTH_TYPE_WPA2_PSK = 4;
-    // Hotspot 2.0 r2 OSEN.
-    AUTH_TYPE_OSEN = 5;
-    // IEEE 802.11r Fast BSS Transition with PSK authentication.
-    AUTH_TYPE_FT_PSK = 6;
-    // IEEE 802.11r Fast BSS Transition with EAP authentication.
-    AUTH_TYPE_FT_EAP = 7;
-    // Simultaneous Authentication of Equals.
-    AUTH_TYPE_SAE = 8;
-    // Opportunistic Wireless Encryption.
-    AUTH_TYPE_OWE = 9;
-    // SUITE_B_192 192 bit level
-    AUTH_TYPE_SUITE_B_192 = 10;
-    // WPA pre-shared key with stronger SHA256-based algorithms.
-    AUTH_TYPE_WPA_PSK_SHA256 = 11;
-    // WPA using EAP authentication with stronger SHA256-based algorithms.
-    AUTH_TYPE_WPA_EAP_SHA256 = 12;
-    // WAPI pre-shared key.
-    AUTH_TYPE_WAPI_PSK = 13;
-    // WAPI certificate to be specified.
-    AUTH_TYPE_WAPI_CERT = 14;
-    // IEEE 802.11ai FILS SK with SHA256.
-    AUTH_TYPE_FILS_SHA256 = 15;
-    // IEEE 802.11ai FILS SK with SHA384.
-    AUTH_TYPE_FILS_SHA384 = 16;
-}
-
-/**
- * Bucketed wifi band.
- */
-enum WifiBandBucket {
-    BAND_UNKNOWN = 0;
-
-    // All of 2.4GHz band
-    BAND_2G = 1;
-    // Frequencies in the range of [5150, 5250) GHz
-    BAND_5G_LOW = 2;
-    // Frequencies in the range of [5250, 5725) GHz
-    BAND_5G_MIDDLE = 3;
-    // Frequencies in the range of [5725, 5850) GHz
-    BAND_5G_HIGH = 4;
-    // Frequencies in the range of [5925, 6425) GHz
-    BAND_6G_LOW = 5;
-    // Frequencies in the range of [6425, 6875) GHz
-    BAND_6G_MIDDLE = 6;
-    // Frequencies in the range of [6875, 7125) GHz
-    BAND_6G_HIGH = 7;
-}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ea667277..60dd0eb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -120,6 +120,12 @@
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
 
+    <protected-broadcast android:name="android.app.action.USER_ADDED" />
+    <protected-broadcast android:name="android.app.action.USER_REMOVED" />
+    <protected-broadcast android:name="android.app.action.USER_STARTED" />
+    <protected-broadcast android:name="android.app.action.USER_STOPPED" />
+    <protected-broadcast android:name="android.app.action.USER_SWITCHED" />
+
     <protected-broadcast android:name="android.app.action.BUGREPORT_SHARING_DECLINED" />
     <protected-broadcast android:name="android.app.action.BUGREPORT_FAILED" />
     <protected-broadcast android:name="android.app.action.BUGREPORT_SHARE" />
@@ -1809,6 +1815,16 @@
     <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows system APK to update Wifi/Cellular coex channels to avoid.
+             <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS"
+        android:protectionLevel="signature" />
+
+    <!-- @SystemApi @hide Allows applications to access Wifi/Cellular coex channels being avoided.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
+                android:protectionLevel="signature|privileged" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -2557,6 +2573,10 @@
     <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
         android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
 
+    <!-- @SystemApi @hide Allows an application to start foreground services from background -->
+    <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
+                android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
+
     <!-- @SystemApi Must be required by activities that handle the intent action
          {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
          hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
@@ -3100,6 +3120,12 @@
     <permission android:name="android.permission.DUMP"
         android:protectionLevel="signature|privileged|development" />
 
+    <!-- Allows an application to start tracing for InputMethod and WindowManager.
+    <p>Not for use by third-party applications.
+    @hide -->
+    <permission android:name="android.permission.CONTROL_UI_TRACING"
+        android:protectionLevel="signature|privileged|development" />
+
     <!-- Allows an application to read the low-level system log files.
     <p>Not for use by third-party applications, because
     Log entries can contain the user's private information. -->
@@ -4186,6 +4212,14 @@
     <permission android:name="android.permission.FACTORY_TEST"
         android:protectionLevel="signature" />
 
+    <!-- @hide @TestApi Allows an application to broadcast the intent {@link
+         android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS}.
+         <p>Not for use by third-party applications.
+    -->
+    <permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"
+        android:protectionLevel="signature|recents" />
+    <uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
+
     <!-- Allows an application to broadcast a notification that an application
          package has been removed.
          <p>Not for use by third-party applications.
@@ -5219,6 +5253,9 @@
              android:label="@string/sensor_notification_service"/>
     <!-- Attribution for Twilight service. -->
     <attribution android:tag="TwilightService" android:label="@string/twilight_service"/>
+    <!-- Attribution for the Offline LocationTimeZoneProvider, used to detect time zone using
+         on-device data -->
+    <attribution android:tag="OfflineLocationTimeZoneProvider" android:label="@string/offline_location_time_zone_detection_service"/>
 
     <application android:process="system"
                  android:persistent="true"
@@ -5685,6 +5722,18 @@
             </intent-filter>
         </service>
 
+        <!-- AOSP configures a default secondary LocationTimeZoneProvider that uses an on-device
+             data set from the com.android.geotz APEX. -->
+        <uses-library android:name="com.android.location.provider" />
+        <service android:name="com.android.timezone.geotz.provider.OfflineLocationTimeZoneService"
+                 android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.location.timezone.service.v1.SecondaryLocationTimeZoneProvider" />
+            </intent-filter>
+            <meta-data android:name="serviceVersion" android:value="1" />
+            <meta-data android:name="serviceIsMultiuser" android:value="true" />
+        </service>
+
         <provider
             android:name="com.android.server.textclassifier.IconsContentProvider"
             android:authorities="com.android.textclassifier.icons"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index b0ee12a..88998f2 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -26,6 +26,18 @@
     android:theme="@style/Theme.DeviceDefault.Notification"
     >
 
+    <ImageView
+        android:id="@+id/left_icon"
+        android:layout_width="@dimen/notification_left_icon_size"
+        android:layout_height="@dimen/notification_left_icon_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_left_icon_start"
+        android:background="@drawable/notification_large_icon_outline"
+        android:importantForAccessibility="no"
+        android:scaleType="centerCrop"
+        android:visibility="gone"
+        />
+
     <com.android.internal.widget.CachingIconView
         android:id="@+id/icon"
         android:layout_width="@dimen/notification_icon_circle_size"
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 69d4a12..0006384 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -23,6 +23,18 @@
     android:tag="base"
     >
 
+    <ImageView
+        android:id="@+id/left_icon"
+        android:layout_width="@dimen/notification_left_icon_size"
+        android:layout_height="@dimen/notification_left_icon_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_left_icon_start"
+        android:background="@drawable/notification_large_icon_outline"
+        android:importantForAccessibility="no"
+        android:scaleType="centerCrop"
+        android:visibility="gone"
+        />
+
     <com.android.internal.widget.CachingIconView
         android:id="@+id/icon"
         android:layout_width="@dimen/notification_icon_circle_size"
@@ -34,7 +46,7 @@
         />
 
     <LinearLayout
-        android:id="@+id/notification_standard_view_column"
+        android:id="@+id/notification_headerless_view_column"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c32e8dc..85b19e7 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -303,6 +303,9 @@
         <!-- Additional flag from base permission type: this permission will be granted to the
              retail demo app, as defined by the OEM. -->
         <flag name="retailDemo" value="0x1000000" />
+        <!-- Additional flag from base permission type: this permission will be granted to the
+             recents app. -->
+        <flag name="recents" value="0x2000000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index eda1c7a..f8cbfeb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1603,7 +1603,7 @@
     <integer name="config_timeZoneRulesCheckRetryCount">5</integer>
 
     <!-- Whether the geolocation time zone detection feature is enabled. -->
-    <bool name="config_enableGeolocationTimeZoneDetection" translatable="false">false</bool>
+    <bool name="config_enableGeolocationTimeZoneDetection" translatable="false">true</bool>
 
     <!-- Whether to enable primary location time zone provider overlay which allows the primary
          location time zone provider to be replaced by an app at run-time. When disabled, only the
@@ -1622,8 +1622,13 @@
          wants to disable the overlay mechanism can set it to false. -->
     <bool name="config_enableSecondaryLocationTimeZoneOverlay" translatable="false">false</bool>
     <!-- Package name providing the secondary location time zone provider. Used only when
-         config_enableSecondaryLocationTimeZoneOverlay is false. -->
-    <string name="config_secondaryLocationTimeZoneProviderPackageName" translatable="false">@null</string>
+         config_enableSecondaryLocationTimeZoneOverlay is false.
+
+         By default, set to "android" to pick up the default LocationTimeZoneProvider configured in
+         the system server's AndroidManifest.xml. See the
+         com.android.location.timezone.service.v1.SecondaryLocationTimeZoneProvider intent-filter
+         definition there for more information. -->
+    <string name="config_secondaryLocationTimeZoneProviderPackageName" translatable="false">android</string>
 
     <!-- Whether to enable network location overlay which allows network location provider to be
          replaced by an app at run-time. When disabled, only the
@@ -4234,6 +4239,35 @@
          If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
     <integer name="config_defaultRefreshRateInZone">0</integer>
 
+    <!-- The display uses different gamma curves for different refresh rates. It's hard for panel
+         vendor to tune the curves to have exact same brightness for different refresh rate. So
+         flicker could be observed at switch time. The issue can be observed on the screen with
+         even full white content at the high brightness. To prevent flickering, we support fixed
+         refresh rates if the display and ambient brightness are equal to or above the provided
+         thresholds. You can define multiple threshold levels as higher brightness environments
+         may have lower display brightness requirements for the flickering is visible. And the
+         high brightness environment could have higher threshold.
+         For example, fixed refresh rate if
+             display brightness >= disp0 && ambient brightness >= amb0
+             || display brightness >= disp1 && ambient brightness >= amb1 -->
+    <integer-array translatable="false" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate">
+         <!--
+           <item>disp0</item>
+           <item>disp1</item>
+        -->
+    </integer-array>
+
+    <integer-array translatable="false" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate">
+         <!--
+           <item>amb0</item>
+           <item>amb1</item>
+        -->
+    </integer-array>
+
+    <!-- Default refresh rate in the high zone defined by brightness and ambient thresholds.
+         If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
+    <integer name="config_fixedRefreshRateInHighZone">0</integer>
+
     <!-- The type of the light sensor to be used by the display framework for things like
          auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
     <string name="config_displayLightSensorType" translatable="false" />
@@ -4517,4 +4551,7 @@
 
     <!-- If true, hide the display cutout with display area -->
     <bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
+
+    <!-- Indicates that default fitness tracker app needs to request sensor and location permissions. -->
+    <bool name="config_trackerAppNeedsPermissions">false</bool>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 19591f6..4bcabff 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -714,6 +714,10 @@
     <dimen name="notification_right_icon_headerless_margin">12dp</dimen>
     <!-- The top margin of the right icon in the "big" notification states -->
     <dimen name="notification_right_icon_big_margin_top">16dp</dimen>
+    <!-- The size of the left icon -->
+    <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen>
+    <!-- The left padding of the left icon -->
+    <dimen name="notification_left_icon_start">@dimen/notification_icon_circle_start</dimen>
     <!-- The alpha of a disabled notification button -->
     <item type="dimen" format="float" name="notification_action_disabled_alpha">0.5</item>
 
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index f77c6f9..a12d2a9 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -194,6 +194,12 @@
   <!-- A tag used to save the index where the custom view is stored -->
   <item type="id" name="notification_custom_view_index_tag" />
 
+  <!-- A tag used to store the margin end for this view when the right icon is visible -->
+  <item type="id" name="tag_margin_end_when_icon_gone" />
+
+  <!-- A tag used to store the margin end for this view when the right icon is gone -->
+  <item type="id" name="tag_margin_end_when_icon_visible" />
+
   <!-- Marks the "copy to clipboard" button in the ChooserActivity -->
   <item type="id" name="chooser_copy_button" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index be6b6b1..8e3a0cb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -433,6 +433,9 @@
     <string name="sensor_notification_service">Sensor Notification Service</string>
     <!-- Attribution for Twilight service. [CHAR LIMIT=NONE]-->
     <string name="twilight_service">Twilight Service</string>
+    <!-- Attribution for Offline LocationTimeZoneDetector service, i.e. one capable of performing
+         time zone lookup using geo-spacial information held on the device. [CHAR LIMIT=NONE]-->
+    <string name="offline_location_time_zone_detection_service">Offline Time Zone Detection Service</string>
 
     <!-- Factory reset warning dialog strings--> <skip />
     <!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 40aae9e..84556d4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -218,7 +218,7 @@
   <java-symbol type="id" name="inbox_text6" />
   <java-symbol type="id" name="status_bar_latest_event_content" />
   <java-symbol type="id" name="notification_main_column" />
-  <java-symbol type="id" name="notification_standard_view_column" />
+  <java-symbol type="id" name="notification_headerless_view_column" />
   <java-symbol type="id" name="sms_short_code_confirm_message" />
   <java-symbol type="id" name="sms_short_code_detail_layout" />
   <java-symbol type="id" name="sms_short_code_detail_message" />
@@ -3070,6 +3070,8 @@
   <java-symbol type="dimen" name="notification_media_image_margin_end" />
   <java-symbol type="id" name="notification_action_list_margin_target" />
   <java-symbol type="dimen" name="notification_action_disabled_alpha" />
+  <java-symbol type="id" name="tag_margin_end_when_icon_visible" />
+  <java-symbol type="id" name="tag_margin_end_when_icon_gone" />
 
   <!-- Override Wake Key Behavior When Screen is Off -->
   <java-symbol type="bool" name="config_wakeOnDpadKeyPress" />
@@ -3811,6 +3813,11 @@
   <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
   <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
 
+  <!-- For fixed refresh rate displays in high brightness-->
+  <java-symbol type="integer" name="config_fixedRefreshRateInHighZone" />
+  <java-symbol type="array" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate" />
+  <java-symbol type="array" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate" />
+
   <!-- For Auto-Brightness -->
   <java-symbol type="string" name="config_displayLightSensorType" />
 
@@ -4103,4 +4110,7 @@
   <java-symbol type="string" name="window_magnification_prompt_content" />
   <java-symbol type="string" name="turn_on_magnification_settings_action" />
   <java-symbol type="string" name="dismiss_action" />
+
+  <java-symbol type="bool" name="config_trackerAppNeedsPermissions"/>
+
 </resources>
diff --git a/core/res/res/xml/config_user_types.xml b/core/res/res/xml/config_user_types.xml
index 5fd8a95..71dfc55 100644
--- a/core/res/res/xml/config_user_types.xml
+++ b/core/res/res/xml/config_user_types.xml
@@ -40,7 +40,7 @@
 and the PROFILE user android.os.usertype.profile.MANAGED) and creates a new PROFILE user type
 (com.example.profilename):
 
-<user-types>
+<user-types version="0">
     <full-type name="android.os.usertype.full.SECONDARY" >
         <default-restrictions no_sms="true" />
     </full-type>
@@ -65,6 +65,11 @@
     <profile-type
         name="com.example.profilename"
         max-allowed-per-parent="2" />
+
+    <change-user-type
+        from="android.os.usertype.profile.MANAGED"
+        to="com.example.profilename"
+        whenVersionLeq="1" />
 </user-types>
 
 Mandatory attributes:
@@ -93,6 +98,10 @@
 Note, however, that default-restrictions refers to the restrictions applied at the time of user
 creation; therefore, the active restrictions of any pre-existing users will not be updated.
 
+The 'change-user-type' tag should be used in conjunction with the 'version' property of
+'user-types'. It defines a type change for all pre-existing users of 'from' type to the new 'to'
+type, if the former 'user-type's version of device is less than or equal to 'whenVersionLeq'.
+
 -->
 <user-types>
 </user-types>
diff --git a/core/tests/coretests/src/android/app/ApplicationLoadersTest.java b/core/tests/coretests/src/android/app/ApplicationLoadersTest.java
index 4b9910c..19e7f80 100644
--- a/core/tests/coretests/src/android/app/ApplicationLoadersTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationLoadersTest.java
@@ -42,7 +42,7 @@
         return new SharedLibraryInfo(
                 zip, null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/,
                 SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/,
-                null /*dependentPackages*/, null /*dependencies*/);
+                null /*dependentPackages*/, null /*dependencies*/, false /*isNative*/);
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 4fe68cd..e5da41c 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -51,6 +51,8 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
@@ -66,6 +68,7 @@
 
 import com.android.internal.content.ReferrerIntent;
 
+import org.junit.After;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -95,6 +98,16 @@
             new ActivityTestRule<>(TestActivity.class, true /* initialTouchMode */,
                     false /* launchActivity */);
 
+    private ArrayList<VirtualDisplay> mCreatedVirtualDisplays;
+
+    @After
+    public void tearDown() {
+        if (mCreatedVirtualDisplays != null) {
+            mCreatedVirtualDisplays.forEach(VirtualDisplay::release);
+            mCreatedVirtualDisplays = null;
+        }
+    }
+
     @Test
     public void testDoubleRelaunch() throws Exception {
         final Activity activity = mActivityTestRule.launchActivity(new Intent());
@@ -410,7 +423,6 @@
             Context appContext = activity.getApplication();
             Configuration originalAppConfig =
                     new Configuration(appContext.getResources().getConfiguration());
-            DisplayManager dm = appContext.getSystemService(DisplayManager.class);
 
             int virtualDisplayWidth;
             int virtualDisplayHeight;
@@ -421,8 +433,8 @@
                 virtualDisplayWidth = 200;
                 virtualDisplayHeight = 100;
             }
-            Display virtualDisplay = dm.createVirtualDisplay("virtual-display",
-                    virtualDisplayWidth, virtualDisplayHeight, 200, null, 0).getDisplay();
+            final Display virtualDisplay = createVirtualDisplay(appContext,
+                    virtualDisplayWidth, virtualDisplayHeight);
             Context virtualDisplayContext = appContext.createDisplayContext(virtualDisplay);
             int originalVirtualDisplayOrientation = virtualDisplayContext.getResources()
                     .getConfiguration().orientation;
@@ -467,7 +479,6 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             Configuration originalActivityConfig =
                     new Configuration(activity.getResources().getConfiguration());
-            DisplayManager dm = activity.getSystemService(DisplayManager.class);
 
             int virtualDisplayWidth;
             int virtualDisplayHeight;
@@ -478,8 +489,8 @@
                 virtualDisplayWidth = 200;
                 virtualDisplayHeight = 100;
             }
-            Display virtualDisplay = dm.createVirtualDisplay("virtual-display",
-                    virtualDisplayWidth, virtualDisplayHeight, 200, null, 0).getDisplay();
+            final Display virtualDisplay = createVirtualDisplay(activity,
+                    virtualDisplayWidth, virtualDisplayHeight);
             Context virtualDisplayContext = activity.createDisplayContext(virtualDisplay);
             int originalVirtualDisplayOrientation = virtualDisplayContext.getResources()
                     .getConfiguration().orientation;
@@ -704,6 +715,17 @@
         return config.seq;
     }
 
+    private Display createVirtualDisplay(Context context, int w, int h) {
+        final DisplayManager dm = context.getSystemService(DisplayManager.class);
+        final VirtualDisplay virtualDisplay = dm.createVirtualDisplay("virtual-display", w, h,
+                200 /* densityDpi */, null /* surface */, 0 /* flags */);
+        if (mCreatedVirtualDisplays == null) {
+            mCreatedVirtualDisplays = new ArrayList<>();
+        }
+        mCreatedVirtualDisplays.add(virtualDisplay);
+        return virtualDisplay.getDisplay();
+    }
+
     private static ActivityClientRecord getActivityClientRecord(Activity activity) {
         final ActivityThread thread = activity.getActivityThread();
         final IBinder token = activity.getActivityToken();
@@ -796,6 +818,14 @@
         volatile CountDownLatch mConfigLatch;
 
         @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            getWindow().getDecorView().setKeepScreenOn(true);
+            setShowWhenLocked(true);
+            setTurnScreenOn(true);
+        }
+
+        @Override
         public void onConfigurationChanged(Configuration config) {
             super.onConfigurationChanged(config);
             mConfig.setTo(config);
diff --git a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
index 27584a5..7552ec4 100644
--- a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
+++ b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
@@ -21,11 +21,18 @@
 import static junit.framework.Assert.assertFalse;
 
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
 
 import android.app.Notification;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.LauncherApps;
 import android.content.pm.ShortcutInfo;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.UserHandle;
@@ -38,26 +45,37 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PeopleSpaceTileTest {
 
     private Context mContext;
+    private final Drawable mDrawable = new ColorDrawable(Color.BLUE);
+    private final Icon mIcon = PeopleSpaceTile.convertDrawableToIcon(mDrawable);
+
+    @Mock
+    private LauncherApps mLauncherApps;
 
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getContext();
+        MockitoAnnotations.initMocks(this);
+        when(mLauncherApps.getShortcutIconDrawable(any(), eq(0))).thenReturn(mDrawable);
     }
 
     @Test
     public void testId() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).build();
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
         assertThat(tile.getId()).isEqualTo("123");
 
-        tile = new PeopleSpaceTile.Builder(new ShortcutInfo.Builder(mContext, "123").build()).setId(
-                "5").build();
+        tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setId("5")
+                .build();
         assertThat(tile.getId()).isEqualTo("5");
 
         tile = new PeopleSpaceTile.Builder("12", null, null, null).build();
@@ -67,11 +85,13 @@
     @Test
     public void testUserName() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).build();
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
         assertThat(tile.getUserName()).isNull();
 
-        tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setUserName("Name 1").build();
+        tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setUserName("Name 1")
+                .build();
         assertThat(tile.getUserName()).isEqualTo("Name 1");
 
         tile = new PeopleSpaceTile.Builder(null, "Name 2", null, null).build();
@@ -81,21 +101,19 @@
     @Test
     public void testUserIcon() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setUserIcon(
-                Icon.createWithResource(mContext, 1)).build();
-        assertThat(tile.getUserIcon().toString()).isEqualTo(
-                Icon.createWithResource(mContext, 1).toString());
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).setUserIcon(
+                mIcon).build();
+        assertThat(tile.getUserIcon().toString()).isEqualTo(mIcon.toString());
 
-        tile = new PeopleSpaceTile.Builder("12", null, Icon.createWithResource(mContext, 2),
+        tile = new PeopleSpaceTile.Builder("12", null, mIcon,
                 null).build();
-        assertThat(tile.getUserIcon().toString()).isEqualTo(
-                Icon.createWithResource(mContext, 2).toString());
+        assertThat(tile.getUserIcon().toString()).isEqualTo(mIcon.toString());
     }
 
     @Test
     public void testContactUri() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setContactUri(
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).setContactUri(
                 Uri.parse("test")).build();
 
         assertThat(tile.getContactUri()).isEqualTo(Uri.parse("test"));
@@ -103,8 +121,10 @@
 
     @Test
     public void testUid() {
-        PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setUid(42).build();
+        PeopleSpaceTile tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setUid(42)
+                .build();
 
         assertThat(tile.getUid()).isEqualTo(42);
     }
@@ -112,12 +132,12 @@
     @Test
     public void testPackageName() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).build();
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
         // Automatically added by creating a ShortcutInfo.
         assertThat(tile.getPackageName()).isEqualTo("com.android.frameworks.coretests");
 
         tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setPackageName(
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).setPackageName(
                 "package.name").build();
         assertThat(tile.getPackageName()).isEqualTo("package.name");
 
@@ -129,36 +149,39 @@
     @Test
     public void testLastInteractionTimestamp() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).build();
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
         assertThat(tile.getLastInteractionTimestamp()).isEqualTo(0L);
 
-        tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setLastInteractionTimestamp(
-                7L).build();
+        tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setLastInteractionTimestamp(7L)
+                .build();
         assertThat(tile.getLastInteractionTimestamp()).isEqualTo(7L);
     }
 
     @Test
     public void testImportantConversation() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).build();
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
         assertFalse(tile.isImportantConversation());
 
-        tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setIsImportantConversation(
-                true).build();
+        tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setIsImportantConversation(true)
+                .build();
         assertTrue(tile.isImportantConversation());
     }
 
     @Test
     public void testHiddenConversation() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).build();
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
         assertFalse(tile.isHiddenConversation());
 
-        tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setIsHiddenConversation(
-                true).build();
+        tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setIsHiddenConversation(true)
+                .build();
         assertTrue(tile.isHiddenConversation());
     }
 
@@ -168,8 +191,10 @@
         StatusBarNotification sbn = new StatusBarNotification("pkg" /* pkg */, "pkg" /* opPkg */,
                 1 /* id */, "" /* tag */, 0 /* uid */, 0 /* initialPid */, 0 /* score */,
                 notification, UserHandle.CURRENT, 0 /* postTime */);
-        PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setNotification(sbn).build();
+        PeopleSpaceTile tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setNotification(sbn)
+                .build();
 
         assertThat(tile.getNotification()).isEqualTo(sbn);
     }
@@ -177,11 +202,13 @@
     @Test
     public void testIntent() {
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).build();
+                new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
         assertThat(tile.getIntent()).isNull();
 
-        tile = new PeopleSpaceTile.Builder(
-                new ShortcutInfo.Builder(mContext, "123").build()).setIntent(new Intent()).build();
+        tile = new PeopleSpaceTile
+                .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+                .setIntent(new Intent())
+                .build();
         assertThat(tile.getIntent().toString()).isEqualTo(new Intent().toString());
 
         tile = new PeopleSpaceTile.Builder("12", null, null, new Intent()).build();
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index c66bac6..82d066f 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -23,7 +23,6 @@
 
 import android.content.Context;
 import android.content.res.AssetManager;
-import android.graphics.fonts.Font;
 import android.graphics.fonts.FontCustomizationParser;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
@@ -49,7 +48,6 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
 import java.util.Locale;
 
 @SmallTest
@@ -133,14 +131,14 @@
     private static void buildSystemFallback(String xml,
             FontCustomizationParser.Result oemCustomization, ArrayMap<String, Typeface> fontMap,
             ArrayMap<String, FontFamily[]> fallbackMap) {
-        final ArrayList<Font> availableFonts = new ArrayList<>();
         try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
             fos.write(xml.getBytes(Charset.forName("UTF-8")));
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
+
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
-                TEST_FONT_DIR, oemCustomization, fallbackMap, availableFonts);
+                TEST_FONT_DIR, oemCustomization, fallbackMap);
         Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
     }
 
@@ -156,12 +154,11 @@
     public void testBuildSystemFallback() {
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final ArrayList<Font> availableFonts = new ArrayList<>();
         final FontCustomizationParser.Result oemCustomization =
                 new FontCustomizationParser.Result();
 
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
-                SYSTEM_FONT_DIR, oemCustomization, fallbackMap, availableFonts);
+                SYSTEM_FONT_DIR, oemCustomization, fallbackMap);
 
         assertNotNull(aliases);
         assertFalse(fallbackMap.isEmpty());
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index 5fa8c4f..392c6b7 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -23,8 +23,11 @@
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
+import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
 import android.os.SharedMemory;
+import android.text.FontConfig;
+import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
@@ -195,8 +198,9 @@
     @Test
     public void testSerialize() throws Exception {
         HashMap<String, Typeface> systemFontMap = new HashMap<>();
-        Typeface.initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
-                SystemFonts.getAliases());
+        Pair<FontConfig.Alias[], Map<String, FontFamily[]>> res =
+                SystemFonts.initializePreinstalledFonts();
+        Typeface.initSystemDefaultTypefaces(systemFontMap, res.second, res.first);
         SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
         Map<String, Typeface> copiedFontMap =
                 Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN));
diff --git a/core/tests/coretests/src/android/security/CredentialManagementAppTest.java b/core/tests/coretests/src/android/security/CredentialManagementAppTest.java
new file mode 100644
index 0000000..366aabd
--- /dev/null
+++ b/core/tests/coretests/src/android/security/CredentialManagementAppTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import android.net.Uri;
+import android.util.Xml;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.Map;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class CredentialManagementAppTest {
+
+    private static final String TEST_PACKAGE_NAME_1 = "com.android.test";
+    private static final String TEST_PACKAGE_NAME_2 = "com.android.test2";
+    private static final Uri TEST_URI_1 = Uri.parse("test.com");
+    private static final Uri TEST_URI_2 = Uri.parse("test2.com");
+    private static final String TEST_ALIAS_1 = "testAlias";
+    private static final String TEST_ALIAS_2 = "testAlias2";
+
+    private static final String PACKAGE_NAME = "com.android.cred.mng.pkg";
+    private static final AppUriAuthenticationPolicy AUTHENTICATION_POLICY =
+            new AppUriAuthenticationPolicy.Builder()
+                    .addAppAndUriMapping(TEST_PACKAGE_NAME_1, TEST_URI_1, TEST_ALIAS_1)
+                    .build();
+    private static final CredentialManagementApp CREDENTIAL_MANAGEMENT_APP =
+            new CredentialManagementApp(PACKAGE_NAME, AUTHENTICATION_POLICY);
+
+    private static final String TAG_CREDENTIAL_MANAGEMENT_APP = "credential-management-app";
+
+    @Test
+    public void credentialManagementApp_getters() {
+        CredentialManagementApp credentialManagementApp =
+                new CredentialManagementApp(PACKAGE_NAME, AUTHENTICATION_POLICY);
+
+        assertThat(credentialManagementApp.getPackageName(), is(PACKAGE_NAME));
+        assertThat(credentialManagementApp.getAuthenticationPolicy(), is(AUTHENTICATION_POLICY));
+    }
+
+    @Test
+    public void setAuthenticationPolicy_updatesAuthenticationPolicy() {
+        CredentialManagementApp credentialManagementApp =
+                new CredentialManagementApp(PACKAGE_NAME, AUTHENTICATION_POLICY);
+        AppUriAuthenticationPolicy updatedAuthenticationPolicy =
+                new AppUriAuthenticationPolicy.Builder().addAppAndUriMapping(
+                        TEST_PACKAGE_NAME_2, TEST_URI_2, TEST_ALIAS_2).build();
+
+        credentialManagementApp.setAuthenticationPolicy(updatedAuthenticationPolicy);
+
+        assertThat(credentialManagementApp.getAuthenticationPolicy(),
+                is(updatedAuthenticationPolicy));
+    }
+
+    @Test
+    public void constructor_nullPackageName_throwException() {
+        try {
+            new CredentialManagementApp(/* packageName= */ null, AUTHENTICATION_POLICY);
+            fail("Shall not take null inputs");
+        } catch (NullPointerException expected) {
+            // Expected behavior, nothing to do.
+        }
+    }
+
+    @Test
+    public void constructor_nullAuthenticationPolicy_throwException() {
+        try {
+            new CredentialManagementApp(PACKAGE_NAME, /* authenticationPolicy= */ null);
+            fail("Shall not take null inputs");
+        } catch (NullPointerException expected) {
+            // Expected behavior, nothing to do.
+        }
+    }
+
+    @Test
+    public void writeToXmlAndReadFromXml() throws IOException, XmlPullParserException {
+        File xmlFile = writeToXml(CREDENTIAL_MANAGEMENT_APP);
+
+        CredentialManagementApp loadedCredentialManagementApp = readFromXml(xmlFile);
+
+        assertCredentialManagementAppsEqual(loadedCredentialManagementApp,
+                CREDENTIAL_MANAGEMENT_APP);
+    }
+
+    private File writeToXml(CredentialManagementApp credentialManagementApp) throws IOException {
+        File file = File.createTempFile("temp", "credmng");
+        final FileOutputStream out = new FileOutputStream(file);
+        XmlSerializer xml = Xml.newSerializer();
+        xml.setOutput(out, StandardCharsets.UTF_8.name());
+        xml.startDocument(null, true);
+        xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        xml.startTag(null, TAG_CREDENTIAL_MANAGEMENT_APP);
+        credentialManagementApp.writeToXml(xml);
+        xml.endTag(null, TAG_CREDENTIAL_MANAGEMENT_APP);
+        xml.endDocument();
+        out.close();
+        return file;
+    }
+
+    private CredentialManagementApp readFromXml(File file)
+            throws IOException, XmlPullParserException {
+        CredentialManagementApp credentialManagementApp = null;
+        final XmlPullParser parser = Xml.newPullParser();
+        final FileInputStream in = new FileInputStream(file);
+        parser.setInput(in, StandardCharsets.UTF_8.name());
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+        }
+        String tag = parser.getName();
+        if (TAG_CREDENTIAL_MANAGEMENT_APP.equals(tag)) {
+            credentialManagementApp = CredentialManagementApp.readFromXml(parser);
+        }
+        return credentialManagementApp;
+    }
+
+    private void assertCredentialManagementAppsEqual(CredentialManagementApp actual,
+            CredentialManagementApp expected) {
+        assertThat(actual.getPackageName(), is(expected.getPackageName()));
+        assertAuthenticationPoliciesEqual(actual.getAuthenticationPolicy(),
+                expected.getAuthenticationPolicy());
+    }
+
+    private void assertAuthenticationPoliciesEqual(AppUriAuthenticationPolicy actual,
+            AppUriAuthenticationPolicy expected) {
+        Iterator<Map.Entry<String, Map<Uri, String>>> actualIter =
+                actual.getAppAndUriMappings().entrySet().iterator();
+        Iterator<Map.Entry<String, Map<Uri, String>>> expectedIter =
+                expected.getAppAndUriMappings().entrySet().iterator();
+
+        assertThat(actual.getAppAndUriMappings().size(),
+                is(expected.getAppAndUriMappings().size()));
+        while (actualIter.hasNext()) {
+            Map.Entry<String, Map<Uri, String>> actualAppToUri = actualIter.next();
+            Map.Entry<String, Map<Uri, String>> expectedAppToUri = expectedIter.next();
+            assertThat(actualAppToUri.getKey(), is(expectedAppToUri.getKey()));
+            assertUrisToAliasesEqual(actualAppToUri.getValue(), expectedAppToUri.getValue());
+        }
+    }
+
+    private void assertUrisToAliasesEqual(Map<Uri, String> actual, Map<Uri, String> expected) {
+        Iterator<Map.Entry<Uri, String>> actualIter = actual.entrySet().iterator();
+        Iterator<Map.Entry<Uri, String>> expectedIter = expected.entrySet().iterator();
+
+        assertThat(actual.size(), is(expected.size()));
+        while (actualIter.hasNext()) {
+            Map.Entry<Uri, String> actualUriToAlias = actualIter.next();
+            Map.Entry<Uri, String> expectedUriToAlias = expectedIter.next();
+            assertThat(actualUriToAlias.getKey(), is(expectedUriToAlias.getKey()));
+            assertThat(actualUriToAlias.getValue(), is(expectedUriToAlias.getValue()));
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index cc51ec3..64e6f82 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.graphics.Typeface;
-import android.graphics.fonts.Font;
 import android.graphics.fonts.FontCustomizationParser;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
@@ -35,7 +34,6 @@
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
 
 public class FontFallbackSetup implements AutoCloseable {
     private final String[] mTestFontFiles;
@@ -78,11 +76,10 @@
         }
 
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final ArrayList<Font> availableFonts = new ArrayList<>();
         final FontCustomizationParser.Result oemCustomization =
                 new FontCustomizationParser.Result();
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml,
-                mTestFontsDir, oemCustomization, fallbackMap, availableFonts);
+                mTestFontsDir, oemCustomization, fallbackMap);
         Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);
     }
 
diff --git a/core/tests/coretests/src/android/widget/NumberPickerTest.java b/core/tests/coretests/src/android/widget/NumberPickerTest.java
new file mode 100644
index 0000000..cab7c89
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/NumberPickerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class NumberPickerTest {
+    @Test
+    public void testAccessibilityFocusedProperty() {
+        final int virtualViewIdIncrement = 1;
+        final int VirtualViewIdInput = 2;
+        final int VirtualViewIdDecrement = 3;
+        final NumberPicker np =
+                new NumberPicker(InstrumentationRegistry.getInstrumentation().getContext());
+        final AccessibilityNodeProvider provider = np.getAccessibilityNodeProvider();
+
+        AccessibilityNodeInfo info = provider.createAccessibilityNodeInfo(View.NO_ID);
+        assertFalse(info.isAccessibilityFocused());
+        info.recycle();
+        provider.performAction(View.NO_ID, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+        info = provider.createAccessibilityNodeInfo(View.NO_ID);
+        assertTrue(info.isAccessibilityFocused());
+        info.recycle();
+
+        info = provider.createAccessibilityNodeInfo(virtualViewIdIncrement);
+        assertFalse(info.isAccessibilityFocused());
+        info.recycle();
+        provider.performAction(
+                virtualViewIdIncrement,
+                AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
+                null
+        );
+        info = provider.createAccessibilityNodeInfo(virtualViewIdIncrement);
+        assertTrue(info.isAccessibilityFocused());
+        info.recycle();
+
+        info = provider.createAccessibilityNodeInfo(VirtualViewIdInput);
+        assertFalse(info.isAccessibilityFocused());
+        info.recycle();
+        provider.performAction(
+                VirtualViewIdInput,
+                AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
+                null
+        );
+        info = provider.createAccessibilityNodeInfo(VirtualViewIdInput);
+        assertTrue(info.isAccessibilityFocused());
+        info.recycle();
+
+        info = provider.createAccessibilityNodeInfo(VirtualViewIdDecrement);
+        assertFalse(info.isAccessibilityFocused());
+        info.recycle();
+        provider.performAction(
+                VirtualViewIdDecrement,
+                AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
+                null
+        );
+        info = provider.createAccessibilityNodeInfo(VirtualViewIdDecrement);
+        assertTrue(info.isAccessibilityFocused());
+        info.recycle();
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 7cde19c..40ef04a 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -376,6 +376,56 @@
     }
 
     @Test
+    public void testToolbarMenuItemClickAfterSelectionChange() throws Throwable {
+        final MenuItem[] latestItem = new MenuItem[1];
+        final MenuItem[] clickedItem = new MenuItem[1];
+        final String text = "abcd efg hijk";
+        mActivityRule.runOnUiThread(() -> {
+            final TextView textView = mActivity.findViewById(R.id.textview);
+            textView.setText(text);
+            textView.setCustomSelectionActionModeCallback(
+                    new ActionMode.Callback() {
+                        @Override
+                        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+                            menu.clear();
+                            latestItem[0] = menu.add("Item");
+                            return true;
+                        }
+
+                        @Override
+                        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+                            clickedItem[0] = item;
+                            return true;
+                        }
+
+                        @Override
+                        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+                            return true;
+                        }
+
+                        @Override
+                        public void onDestroyActionMode(ActionMode mode) {}
+                    });
+        });
+        mInstrumentation.waitForIdleSync();
+
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
+        sleepForFloatingToolbarPopup();
+
+        // Change the selection so that the menu items are refreshed.
+        final TextView textView = mActivity.findViewById(R.id.textview);
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, 0));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
+        clickFloatingToolbarItem("Item");
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(latestItem[0], clickedItem[0]);
+    }
+
+    @Test
     public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
         final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
         final int position = (textLink.getStart() + textLink.getEnd()) / 2;
diff --git a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
index 7b9283b..9978648 100644
--- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
@@ -16,11 +16,11 @@
 
 package android.widget;
 
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_CLIPBOARD;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_PROCESS_TEXT;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_CLIPBOARD;
+import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
+import static android.view.ContentInfo.SOURCE_INPUT_METHOD;
+import static android.view.ContentInfo.SOURCE_PROCESS_TEXT;
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
 
 import static androidx.test.espresso.Espresso.onView;
@@ -41,7 +41,7 @@
 import android.content.ClipDescription;
 import android.net.Uri;
 import android.os.Bundle;
-import android.view.OnReceiveContentListener;
+import android.view.ContentInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnectionWrapper;
 import android.view.inputmethod.InputContentInfo;
@@ -133,8 +133,8 @@
         // InputConnection.commitContent.
         ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
         ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
-        OnReceiveContentListener.Payload payload =
-                new OnReceiveContentListener.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+        ContentInfo payload =
+                new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
         mDefaultReceiver.onReceiveContent(mEditText, payload);
         verify(ic.mMock, times(1))
                 .commitContent(any(InputContentInfo.class), eq(0), eq(null));
@@ -155,8 +155,8 @@
         // Invoke the listener and assert that the InputConnection is not invoked.
         ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
         ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
-        OnReceiveContentListener.Payload payload =
-                new OnReceiveContentListener.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+        ContentInfo payload =
+                new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
         mDefaultReceiver.onReceiveContent(mEditText, payload);
         verifyZeroInteractions(ic.mMock);
     }
@@ -176,20 +176,20 @@
         // trigger calls to InputConnection.commitContent.
         ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
         ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
-        OnReceiveContentListener.Payload payload =
-                new OnReceiveContentListener.Payload.Builder(clip, SOURCE_CLIPBOARD).build();
+        ContentInfo payload =
+                new ContentInfo.Builder(clip, SOURCE_CLIPBOARD).build();
         mDefaultReceiver.onReceiveContent(mEditText, payload);
         verifyZeroInteractions(ic.mMock);
 
-        payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_INPUT_METHOD).build();
+        payload = new ContentInfo.Builder(clip, SOURCE_INPUT_METHOD).build();
         mDefaultReceiver.onReceiveContent(mEditText, payload);
         verifyZeroInteractions(ic.mMock);
 
-        payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_DRAG_AND_DROP).build();
+        payload = new ContentInfo.Builder(clip, SOURCE_DRAG_AND_DROP).build();
         mDefaultReceiver.onReceiveContent(mEditText, payload);
         verifyZeroInteractions(ic.mMock);
 
-        payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_PROCESS_TEXT).build();
+        payload = new ContentInfo.Builder(clip, SOURCE_PROCESS_TEXT).build();
         mDefaultReceiver.onReceiveContent(mEditText, payload);
         verifyZeroInteractions(ic.mMock);
     }
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index d45d4b0..4779786 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -28,10 +28,11 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static com.android.internal.widget.FloatingToolbar.MenuItemRepr;
+
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.is;
 
-import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -158,8 +159,8 @@
             public void describeTo(Description description) {}
 
             private void collectMenuItemIds(View view) {
-                if (view.getTag() instanceof MenuItem) {
-                    menuItemIds.add(((MenuItem) view.getTag()).getItemId());
+                if (view.getTag() instanceof MenuItemRepr) {
+                    menuItemIds.add(((MenuItemRepr) view.getTag()).itemId);
                 } else if (view instanceof ViewGroup) {
                     ViewGroup viewGroup = (ViewGroup) view;
                     for (int i = 0; i < viewGroup.getChildCount(); i++) {
@@ -178,8 +179,8 @@
      */
     public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
         final Predicate<View> hasMenuItemLabel = view ->
-                view.getTag() instanceof MenuItem
-                        && itemLabel.equals(((MenuItem) view.getTag()).getTitle().toString());
+                view.getTag() instanceof MenuItemRepr
+                        && itemLabel.equals(((MenuItemRepr) view.getTag()).title);
         assertFloatingToolbarMenuItem(hasMenuItemLabel, false);
     }
 
@@ -191,8 +192,8 @@
      */
     public static void assertFloatingToolbarDoesNotContainItem(final int menuItemId) {
         final Predicate<View> hasMenuItemId = view ->
-                view.getTag() instanceof MenuItem
-                        && ((MenuItem) view.getTag()).getItemId() == menuItemId;
+                view.getTag() instanceof MenuItemRepr
+                        && ((MenuItemRepr) view.getTag()).itemId == menuItemId;
         assertFloatingToolbarMenuItem(hasMenuItemId, false);
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index 2402420..7f7bfa3 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -77,7 +77,8 @@
 
         Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
         mTracker = Mockito.spy(
-                new FrameTracker(session, handler, mRenderer, mWrapper, 1, -1));
+                new FrameTracker(session, handler, mRenderer, mWrapper,
+                        /*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1));
         doNothing().when(mTracker).triggerPerfetto();
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 474cb1d..0ef5643 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -94,7 +94,8 @@
         Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
         FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
                 new ThreadedRendererWrapper(mView.getThreadedRenderer()),
-                new FrameMetricsWrapper(), 1, -1));
+                new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
+                /*traceThresholdFrameTimeMillis=*/ -1));
         doReturn(tracker).when(monitor).createFrameTracker(any());
 
         // Simulate a trace session and see if begin / end are invoked.
@@ -150,7 +151,8 @@
         Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
         FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
                 new ThreadedRendererWrapper(mView.getThreadedRenderer()),
-                new FrameMetricsWrapper(), 1, -1));
+                new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
+                /*traceThresholdFrameTimeMillis=*/ -1));
         doReturn(tracker).when(monitor).createFrameTracker(any());
 
         assertThat(monitor.begin(session.getCuj())).isTrue();
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 75dd7fb..ff1d965c 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -192,8 +192,8 @@
         }
 
         @Override
-        public Future<?> scheduleCpuSyncDueToScreenStateChange(
-                boolean onBattery, boolean onBatteryScreenOff) {
+        public Future<?> scheduleSyncDueToScreenStateChange(
+                int flag, boolean onBattery, boolean onBatteryScreenOff, int screenState) {
             return null;
         }
 
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
new file mode 100644
index 0000000..88295ef
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.power;
+
+import static com.android.internal.power.MeasuredEnergyArray.NUMBER_SUBSYSTEMS;
+import static com.android.internal.power.MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
+import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE;
+import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON;
+import static com.android.internal.power.MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.view.Display;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link MeasuredEnergyStats}.
+ *
+ * To run the tests, use
+ * atest FrameworksCoreTests:com.android.internal.power.MeasuredEnergyStatsTest
+ */
+public class MeasuredEnergyStatsTest {
+    private MeasuredEnergyStats mStats;
+    private int[] mAllSubsystems = new int[NUMBER_SUBSYSTEMS];
+    private long[] mCurrentSubsystemEnergyUJ = new long[NUMBER_SUBSYSTEMS];
+
+    MeasuredEnergyArray mMeasuredEnergyArray = new MeasuredEnergyArray() {
+        @Override
+        public int getSubsystem(int index) {
+            return mAllSubsystems[index];
+        }
+
+        @Override
+        public long getEnergy(int index) {
+            return mCurrentSubsystemEnergyUJ[index];
+        }
+
+        @Override
+        public int size() {
+            return NUMBER_SUBSYSTEMS;
+        }
+    };
+
+    @Before
+    public void setUp() {
+        // Populate all supported subsystems indexes and arbitrary starting energy values.
+        mAllSubsystems[SUBSYSTEM_DISPLAY] = SUBSYSTEM_DISPLAY;
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] = 111;
+
+        mStats = new MeasuredEnergyStats(mMeasuredEnergyArray, Display.STATE_UNKNOWN);
+    }
+
+    @Test
+    public void testReadWriteParcel() {
+        // update with some arbitrary data
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 222;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_ON, true);
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 321;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_DOZE, true);
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 456;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+        final Parcel parcel = Parcel.obtain();
+        mStats.writeToParcel(parcel);
+
+        parcel.setDataPosition(0);
+        MeasuredEnergyStats stats = new MeasuredEnergyStats(parcel);
+
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            assertEquals(mStats.getAccumulatedBucketEnergy(i), stats.getAccumulatedBucketEnergy(i));
+        }
+        parcel.recycle();
+    }
+
+    @Test
+    public void testReadWriteSummaryParcel() {
+        // update with some arbitrary data
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 222;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_ON, true);
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 321;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_DOZE, true);
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 456;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+        final Parcel parcel = Parcel.obtain();
+        MeasuredEnergyStats.writeSummaryToParcel(mStats, parcel);
+
+        parcel.setDataPosition(0);
+        MeasuredEnergyStats stats = new MeasuredEnergyStats(mMeasuredEnergyArray,
+                Display.STATE_UNKNOWN);
+        MeasuredEnergyStats.readSummaryFromParcel(stats, parcel);
+
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            assertEquals(mStats.getAccumulatedBucketEnergy(i), stats.getAccumulatedBucketEnergy(i));
+        }
+        parcel.recycle();
+    }
+
+    @Test
+    public void testDisplayStateEnergyAttribution() {
+        long expectedScreenOnEnergy = 0;
+        long expectedScreenDozeEnergy = 0;
+
+        // Display energy should be attributed to the previous screen state.
+        mStats.update(mMeasuredEnergyArray, Display.STATE_UNKNOWN, true);
+
+        incrementDisplayState(222, Display.STATE_ON, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenOnEnergy += 321;
+        incrementDisplayState(321, Display.STATE_DOZE, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenDozeEnergy += 456;
+        incrementDisplayState(456, Display.STATE_OFF, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        incrementDisplayState(1111, Display.STATE_DOZE_SUSPEND, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenDozeEnergy += 2345;
+        incrementDisplayState(2345, Display.STATE_ON_SUSPEND, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenOnEnergy += 767;
+        incrementDisplayState(767, Display.STATE_VR, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenOnEnergy += 999;
+        incrementDisplayState(999, Display.STATE_UNKNOWN, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+    }
+
+    @Test
+    public void testDisplayStateEnergyAttribution_notRunning() {
+        long expectedScreenOnEnergy = 0;
+        long expectedScreenDozeEnergy = 0;
+
+        // Display energy should be attributed to the previous screen state.
+        mStats.update(mMeasuredEnergyArray, Display.STATE_UNKNOWN, true);
+
+        incrementDisplayState(222, Display.STATE_ON, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenOnEnergy += 321;
+        incrementDisplayState(321, Display.STATE_DOZE, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        // Updates after this point should not result in energy accumulation.
+        incrementDisplayState(456, Display.STATE_OFF, false, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        incrementDisplayState(1111, Display.STATE_DOZE_SUSPEND, false, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        incrementDisplayState(2345, Display.STATE_ON_SUSPEND, false, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        incrementDisplayState(767, Display.STATE_VR, false, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        // Resume energy accumulation.
+        expectedScreenOnEnergy += 999;
+        incrementDisplayState(999, Display.STATE_UNKNOWN, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+    }
+
+    @Test
+    public void testReset() {
+        // update with some arbitrary data.
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 222;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_ON, true);
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 321;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_DOZE, true);
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += 456;
+        mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+        mStats.reset();
+        // All energy should be reset to 0
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            assertEquals(mStats.getAccumulatedBucketEnergy(i), 0);
+        }
+
+        // Increment all subsystem energy by some arbitrary amount and update
+        for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+            mCurrentSubsystemEnergyUJ[i] += 100 * i;
+        }
+        mStats.update(mMeasuredEnergyArray, Display.STATE_OFF, true);
+
+        // All energy should still be 0 after the first post-reset update.
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            assertEquals(mStats.getAccumulatedBucketEnergy(i), 0);
+        }
+
+        // Energy accumulation should continue like normal.
+        long expectedScreenOnEnergy = 0;
+        long expectedScreenDozeEnergy = 0;
+        incrementDisplayState(222, Display.STATE_ON, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenOnEnergy += 321;
+        incrementDisplayState(321, Display.STATE_DOZE, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+
+        expectedScreenDozeEnergy += 456;
+        incrementDisplayState(456, Display.STATE_OFF, true, expectedScreenOnEnergy,
+                expectedScreenDozeEnergy);
+    }
+
+    @Test
+    public void testHasSubsystem() {
+        for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+            assertEquals(mStats.hasSubsystem(i), true);
+        }
+    }
+
+    @Test
+    public void testHasSubsystem_unavailable() {
+        // Setup MeasuredEnergyStats with not available subsystems.
+        int[] subsystems = new int[0];
+        long[] energies = new long[0];
+        MeasuredEnergyArray measuredEnergyArray = new MeasuredEnergyArray() {
+            @Override
+            public int getSubsystem(int index) {
+                return subsystems[index];
+            }
+
+            @Override
+            public long getEnergy(int index) {
+                return energies[index];
+            }
+
+            @Override
+            public int size() {
+                return 0;
+            }
+        };
+        MeasuredEnergyStats stats = new MeasuredEnergyStats(measuredEnergyArray,
+                Display.STATE_UNKNOWN);
+
+        for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+            assertEquals(stats.hasSubsystem(i), false);
+        }
+
+        stats.reset();
+        // a reset should not change the state of an unavailable subsystem.
+        for (int i = 0; i < NUMBER_SUBSYSTEMS; i++) {
+            assertEquals(stats.hasSubsystem(i), false);
+        }
+    }
+
+    private void incrementDisplayState(long deltaEnergy, int nextState, boolean accumulate,
+            long expectScreenEnergy, long expectedDozeEnergy) {
+        mCurrentSubsystemEnergyUJ[SUBSYSTEM_DISPLAY] += deltaEnergy;
+        mStats.update(mMeasuredEnergyArray, nextState, accumulate);
+        assertEquals(expectScreenEnergy,
+                mStats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
+        assertEquals(expectedDozeEnergy,
+                mStats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_DOZE));
+    }
+}
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index 2194d4b..4755e0e 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -19,6 +19,7 @@
     static_libs: [
         "androidx.test.rules",
         "frameworks-base-testutils",
+        "guava-android-testlib",
         "truth-prebuilt",
     ],
     libs: ["android.test.runner"],
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
new file mode 100755
index 0000000..4c0de62
--- /dev/null
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import androidx.test.filters.SmallTest;
+
+import com.google.common.testing.EqualsTester;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link HdmiDeviceInfo} */
+@RunWith(JUnit4.class)
+@SmallTest
+public class HdmiDeviceInfoTest {
+
+    @Test
+    public void testEquals() {
+        int logicalAddr = 0x00;
+        int phyAddr = 0x1000;
+        int portId = 1;
+        int deviceType = 0;
+        int vendorId = 0x123456;
+        String displayName = "test device";
+        int powerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
+        int deviceId = 3;
+        int adopterId = 2;
+
+        new EqualsTester()
+                .addEqualityGroup(new HdmiDeviceInfo())
+                .addEqualityGroup(
+                        new HdmiDeviceInfo(phyAddr, portId), new HdmiDeviceInfo(phyAddr, portId))
+                .addEqualityGroup(
+                        new HdmiDeviceInfo(phyAddr, portId, adopterId, deviceId),
+                        new HdmiDeviceInfo(phyAddr, portId, adopterId, deviceId))
+                .addEqualityGroup(
+                        new HdmiDeviceInfo(
+                                logicalAddr, phyAddr, portId, deviceType, vendorId, displayName),
+                        new HdmiDeviceInfo(
+                                logicalAddr, phyAddr, portId, deviceType, vendorId, displayName))
+                .addEqualityGroup(
+                        new HdmiDeviceInfo(
+                                logicalAddr,
+                                phyAddr,
+                                portId,
+                                deviceType,
+                                vendorId,
+                                displayName,
+                                powerStatus),
+                        new HdmiDeviceInfo(
+                                logicalAddr,
+                                phyAddr,
+                                portId,
+                                deviceType,
+                                vendorId,
+                                displayName,
+                                powerStatus))
+                .testEquals();
+    }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
index 099ee22..7aeb86a 100644
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
@@ -17,6 +17,7 @@
 package com.android.frameworks.core.powerstatsviewer;
 
 import android.content.Context;
+import android.os.BatteryStats;
 import android.os.Process;
 
 import com.android.internal.os.BatterySipper;
@@ -32,6 +33,15 @@
     private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
             PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
 
+    // Temporary placeholder voltage for converting energy to charge
+    // TODO: remove this when b/173765509 is resolved
+    private static final double MOCK_NOMINAL_VOLTAGE = 3.7;
+
+    // Unit conversion:
+    //   mAh = uWs * (1/1000)(milli/micro) * (1/Voltage) * (1/3600)(hours/second)
+    private static final double UJ_2_MAH =
+            (1.0 / 1000) * (1.0 / MOCK_NOMINAL_VOLTAGE) * (1.0 / 3600);
+
     enum EntryType {
         POWER,
         DURATION,
@@ -50,6 +60,7 @@
     public PowerStatsData(Context context, BatteryStatsHelper batteryStatsHelper,
             String powerConsumerId) {
         List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
+        BatteryStats batteryStats = batteryStatsHelper.getStats();
 
         double totalPowerMah = 0;
         double totalSmearedPowerMah = 0;
@@ -125,6 +136,8 @@
             totalVideoTimeMs += sipper.videoTimeMs;
         }
 
+        long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy();
+
         if (requestedPowerConsumer == null) {
             mPowerConsumerInfo = null;
             return;
@@ -135,10 +148,18 @@
 
         addEntry("Total power", EntryType.POWER,
                 requestedPowerConsumer.totalSmearedPowerMah, totalSmearedPowerMah);
+        maybeAddMeasuredEnergyEntry(requestedPowerConsumer.drainType, batteryStats);
+
         addEntry("... excluding system", EntryType.POWER,
                 requestedPowerConsumer.totalSmearedPowerMah, totalPowerExcludeSystemMah);
         addEntry("Screen, smeared", EntryType.POWER,
                 requestedPowerConsumer.screenPowerMah, totalScreenPower);
+        if (totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
+            final double measuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
+            final double ratio = measuredCharge / totalScreenPower;
+            addEntry("Screen, smeared (PowerStatsHal adjusted)", EntryType.POWER,
+                    requestedPowerConsumer.screenPowerMah * ratio, measuredCharge);
+        }
         addEntry("Other, smeared", EntryType.POWER,
                 requestedPowerConsumer.proportionalSmearMah, totalProportionalSmearMah);
         addEntry("Excluding smeared", EntryType.POWER,
@@ -218,6 +239,28 @@
         mEntries.add(entry);
     }
 
+    private void maybeAddMeasuredEnergyEntry(BatterySipper.DrainType drainType,
+            BatteryStats batteryStats) {
+        switch (drainType) {
+            case AMBIENT_DISPLAY:
+                final long totalDozeMeasuredEnergyUJ = batteryStats.getScreenDozeEnergy();
+                if (totalDozeMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
+                    final double measuredCharge = UJ_2_MAH * totalDozeMeasuredEnergyUJ;
+                    addEntry("Measured ambient display power", EntryType.POWER, measuredCharge,
+                            measuredCharge);
+                }
+                break;
+            case SCREEN:
+                final long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy();
+                if (totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
+                    final double measuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
+                    addEntry("Measured screen power", EntryType.POWER, measuredCharge,
+                            measuredCharge);
+                }
+                break;
+        }
+    }
+
     public PowerConsumerInfoHelper.PowerConsumerInfo getPowerConsumerInfo() {
         return mPowerConsumerInfo;
     }
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
index 78f2b91..0567910 100644
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
@@ -29,6 +29,7 @@
 import android.widget.TextView;
 
 import androidx.activity.ComponentActivity;
+import androidx.activity.result.ActivityResultLauncher;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.loader.app.LoaderManager;
@@ -60,6 +61,8 @@
     private RecyclerView mPowerStatsDataView;
     private View mLoadingView;
     private View mEmptyView;
+    private ActivityResultLauncher<Void> mStartAppPicker = registerForActivityResult(
+            PowerConsumerPickerActivity.CONTRACT, this::onApplicationSelected);
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -105,8 +108,7 @@
     }
 
     private void startAppPicker() {
-        registerForActivityResult(PowerConsumerPickerActivity.CONTRACT, this::onApplicationSelected)
-                .launch(null);
+        mStartAppPicker.launch(null);
     }
 
     private void onApplicationSelected(String powerConsumerId) {
diff --git a/data/etc/com.android.provision.xml b/data/etc/com.android.provision.xml
index 05404ef..d2ea0ec 100644
--- a/data/etc/com.android.provision.xml
+++ b/data/etc/com.android.provision.xml
@@ -17,5 +17,7 @@
 <permissions>
     <privapp-permissions package="com.android.provision">
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+        <permissionn ame="android.permission.DISPATCH_PROVISIONING_MESSAGE"/>
+        <permission name="android.permission.MASTER_CLEAR"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8406fdf..1fb63f0 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -322,6 +322,7 @@
         <permission name="android.permission.DELETE_CACHE_FILES"/>
         <permission name="android.permission.DELETE_PACKAGES"/>
         <permission name="android.permission.DUMP"/>
+        <permission name="android.permission.CONTROL_UI_TRACING"/>
         <permission name="android.permission.ACTIVITY_EMBEDDING"/>
         <permission name="android.permission.FORCE_STOP_PACKAGES"/>
         <permission name="android.permission.GET_APP_OPS_STATS"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 52da707..6bcab8a 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -961,6 +961,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
     },
+    "-948446688": {
+      "message": "Create TaskDisplayArea uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
     "-937498525": {
       "message": "Executing finish of failed to pause activity: %s",
       "level": "VERBOSE",
@@ -1273,6 +1279,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/Task.java"
     },
+    "-597091183": {
+      "message": "Delete TaskDisplayArea uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
     "-593535526": {
       "message": "Binding proc %s with config %s",
       "level": "VERBOSE",
@@ -1495,12 +1507,6 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "-371630969": {
-      "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
     "-354571697": {
       "message": "Existence Changed in transition %d: %s",
       "level": "VERBOSE",
@@ -1555,6 +1561,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-292790591": {
+      "message": "Attempted to set IME policy to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
     "-279436615": {
       "message": "Moving to PAUSING: %s",
       "level": "VERBOSE",
@@ -1813,12 +1825,6 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "91350919": {
-      "message": "Attempted to set IME flag to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
     "94402792": {
       "message": "Moving to RESUMED: %s (in existing)",
       "level": "VERBOSE",
@@ -1831,12 +1837,6 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "95281111": {
-      "message": "Attempted to get IME flag of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
     "95902367": {
       "message": "Relayout of %s: focusMayChange=%b",
       "level": "VERBOSE",
@@ -2101,12 +2101,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "355940361": {
-      "message": "Config is destroying non-running %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "371173718": {
       "message": "finishSync cancel=%b for %s",
       "level": "VERBOSE",
@@ -2749,6 +2743,18 @@
       "group": "WM_SHOW_SURFACE_ALLOC",
       "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
     },
+    "1100065297": {
+      "message": "Attempted to get IME policy of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1105210816": {
+      "message": "Skipping config check in destroyed state %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1112047265": {
       "message": "finishDrawingWindow: %s mDrawState=%s",
       "level": "DEBUG",
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index a7f2739..cb4dd9e 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -1163,7 +1163,7 @@
             // heuristic we don't need to be always 100% correct.
             Mode activeMode = display.getMode();
             nInitDisplayInfo(activeMode.getPhysicalWidth(), activeMode.getPhysicalHeight(),
-                    activeMode.getRefreshRate(), maxRefreshRate,
+                    display.getRefreshRate(), maxRefreshRate,
                     wideColorDataspace.mNativeDataspace, display.getAppVsyncOffsetNanos(),
                     display.getPresentationDeadlineNanos());
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 712349a..36ef0a4 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -44,6 +44,7 @@
 import android.util.Base64;
 import android.util.LongSparseArray;
 import android.util.LruCache;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -1321,8 +1322,9 @@
     /** @hide */
     public static void loadPreinstalledSystemFontMap() {
         final HashMap<String, Typeface> systemFontMap = new HashMap<>();
-        initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
-                SystemFonts.getAliases());
+        Pair<FontConfig.Alias[], Map<String, FontFamily[]>> pair =
+                SystemFonts.initializePreinstalledFonts();
+        initSystemDefaultTypefaces(systemFontMap, pair.second, pair.first);
         setSystemFontMap(systemFontMap);
     }
 
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 95c4706..3635adc 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -22,7 +22,9 @@
 import android.text.FontConfig;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
@@ -51,9 +53,9 @@
 
     private SystemFonts() {}  // Do not instansiate.
 
-    private static final Map<String, FontFamily[]> sSystemFallbackMap;
-    private static final FontConfig.Alias[] sAliases;
-    private static final List<Font> sAvailableFonts;
+    private static final Object LOCK = new Object();
+    private static @GuardedBy("sLock") Set<Font> sAvailableFonts;
+    private static @GuardedBy("sLock") Map<String, FontFamily[]> sFamilyMap;
 
     /**
      * Returns all available font files in the system.
@@ -61,29 +63,24 @@
      * @return a set of system fonts
      */
     public static @NonNull Set<Font> getAvailableFonts() {
-        HashSet<Font> set = new HashSet<>();
-        set.addAll(sAvailableFonts);
-        return set;
-    }
+        synchronized (LOCK) {
+            if (sAvailableFonts != null) {
+                return sAvailableFonts;
+            }
 
-    /**
-     * Returns raw system fallback map.
-     *
-     * This method is intended to be used only by Typeface static initializer.
-     * @hide
-     */
-    public static @NonNull Map<String, FontFamily[]> getRawSystemFallbackMap() {
-        return sSystemFallbackMap;
-    }
+            Set<Font> set = new HashSet<>();
 
-    /**
-     * Returns a list of aliases.
-     *
-     * This method is intended to be used only by Typeface static initializer.
-     * @hide
-     */
-    public static @NonNull FontConfig.Alias[] getAliases() {
-        return sAliases;
+            for (FontFamily[] items : sFamilyMap.values()) {
+                for (FontFamily family : items) {
+                    for (int i = 0; i < family.getSize(); ++i) {
+                        set.add(family.getFont(i));
+                    }
+                }
+            }
+
+            sAvailableFonts = Collections.unmodifiableSet(set);
+            return sAvailableFonts;
+        }
     }
 
     private static @Nullable ByteBuffer mmap(@NonNull String fullPath) {
@@ -98,8 +95,7 @@
 
     private static void pushFamilyToFallback(@NonNull FontConfig.Family xmlFamily,
             @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
-            @NonNull Map<String, ByteBuffer> cache,
-            @NonNull ArrayList<Font> availableFonts) {
+            @NonNull Map<String, ByteBuffer> cache) {
 
         final String languageTags = xmlFamily.getLanguages();
         final int variant = xmlFamily.getVariant();
@@ -123,7 +119,7 @@
         }
 
         final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
-                xmlFamily.getName(), defaultFonts, languageTags, variant, cache, availableFonts);
+                xmlFamily.getName(), defaultFonts, languageTags, variant, cache);
 
         // Insert family into fallback map.
         for (int i = 0; i < fallbackMap.size(); i++) {
@@ -135,8 +131,7 @@
                 }
             } else {
                 final FontFamily family = createFontFamily(
-                        xmlFamily.getName(), fallback, languageTags, variant, cache,
-                        availableFonts);
+                        xmlFamily.getName(), fallback, languageTags, variant, cache);
                 if (family != null) {
                     fallbackMap.valueAt(i).add(family);
                 } else if (defaultFamily != null) {
@@ -152,8 +147,7 @@
             @NonNull List<FontConfig.Font> fonts,
             @NonNull String languageTags,
             @FontConfig.Family.Variant int variant,
-            @NonNull Map<String, ByteBuffer> cache,
-            @NonNull ArrayList<Font> availableFonts) {
+            @NonNull Map<String, ByteBuffer> cache) {
         if (fonts.size() == 0) {
             return null;
         }
@@ -187,7 +181,6 @@
                 throw new RuntimeException(e);  // Never reaches here
             }
 
-            availableFonts.add(font);
             if (b == null) {
                 b = new FontFamily.Builder(font);
             } else {
@@ -199,12 +192,11 @@
 
     private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily,
             @NonNull HashMap<String, ByteBuffer> bufferCache,
-            @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap,
-            @NonNull ArrayList<Font> availableFonts) {
+            @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap) {
         final String familyName = xmlFamily.getName();
         final FontFamily family = createFontFamily(
                 familyName, Arrays.asList(xmlFamily.getFonts()),
-                xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, availableFonts);
+                xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache);
         if (family == null) {
             return;
         }
@@ -227,8 +219,7 @@
     public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
             @NonNull String fontDir,
             @NonNull FontCustomizationParser.Result oemCustomization,
-            @NonNull ArrayMap<String, FontFamily[]> fallbackMap,
-            @NonNull ArrayList<Font> availableFonts) {
+            @NonNull Map<String, FontFamily[]> fallbackMap) {
         try {
             final FileInputStream fontsIn = new FileInputStream(xmlPath);
             final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir);
@@ -243,12 +234,12 @@
                 if (familyName == null) {
                     continue;
                 }
-                appendNamedFamily(xmlFamily, bufferCache, fallbackListMap, availableFonts);
+                appendNamedFamily(xmlFamily, bufferCache, fallbackListMap);
             }
 
             for (int i = 0; i < oemCustomization.mAdditionalNamedFamilies.size(); ++i) {
                 appendNamedFamily(oemCustomization.mAdditionalNamedFamilies.get(i),
-                        bufferCache, fallbackListMap, availableFonts);
+                        bufferCache, fallbackListMap);
             }
 
             // Then, add fallback fonts to the each fallback map.
@@ -257,7 +248,7 @@
                 // The first family (usually the sans-serif family) is always placed immediately
                 // after the primary family in the fallback.
                 if (i == 0 || xmlFamily.getName() == null) {
-                    pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, availableFonts);
+                    pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache);
                 }
             }
 
@@ -292,14 +283,17 @@
         }
     }
 
-    static {
-        final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>();
-        final ArrayList<Font> availableFonts = new ArrayList<>();
+    /** @hide */
+    public static @NonNull Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
+            initializePreinstalledFonts() {
         final FontCustomizationParser.Result oemCustomization =
                 readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
-        sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
-                oemCustomization, systemFallbackMap, availableFonts);
-        sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap);
-        sAvailableFonts = Collections.unmodifiableList(availableFonts);
+        Map<String, FontFamily[]> map = new ArrayMap<>();
+        FontConfig.Alias[] aliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
+                oemCustomization, map);
+        synchronized (LOCK) {
+            sFamilyMap = map;
+        }
+        return new Pair(aliases, map);
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
similarity index 85%
copy from tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
copy to keystore/java/android/security/AppUriAuthenticationPolicy.aidl
index 6bc9dcb..5c52c86 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+package android.security;
 
-internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
+parcelable AppUriAuthenticationPolicy;
diff --git a/keystore/java/android/security/AppUriAuthenticationPolicy.java b/keystore/java/android/security/AppUriAuthenticationPolicy.java
new file mode 100644
index 0000000..0244ce9
--- /dev/null
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * The app-URI authentication policy is set by the credential management app. This policy determines
+ * which alias for a private key and certificate pair should be used for authentication.
+ * <p>
+ * The authentication policy should be added as a parameter when calling
+ * {@link KeyChain#createManageCredentialsIntent}.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *     AppUriAuthenticationPolicy authenticationPolicy = new AppUriAuthenticationPolicy.Builder()
+ *              .addAppAndUriMapping("com.test.pkg", testUri, "testAlias")
+ *              .addAppAndUriMapping("com.test2.pkg", testUri1, "testAlias2")
+ *              .addAppAndUriMapping("com.test2.pkg", testUri2, "testAlias2")
+ *              .build();
+ *     Intent requestIntent = KeyChain.createManageCredentialsIntent(authenticationPolicy);
+ * }</pre>
+ * <p>
+ */
+public final class AppUriAuthenticationPolicy implements Parcelable {
+
+    private static final String KEY_AUTHENTICATION_POLICY_APP_TO_URIS =
+            "authentication_policy_app_to_uris";
+    private static final String KEY_AUTHENTICATION_POLICY_APP = "policy_app";
+
+    /**
+     * The mappings from an app and list of URIs to a list of aliases, which will be used for
+     * authentication.
+     * <p>
+     * appPackageName -> uri -> alias
+     */
+    @NonNull
+    private final Map<String, UrisToAliases> mAppToUris;
+
+    private AppUriAuthenticationPolicy(@NonNull Map<String, UrisToAliases> appToUris) {
+        Objects.requireNonNull(appToUris);
+        this.mAppToUris = appToUris;
+    }
+
+    /**
+     * Builder class for {@link AppUriAuthenticationPolicy} objects.
+     */
+    public static final class Builder {
+        private Map<String, UrisToAliases> mPackageNameToUris;
+
+        /**
+         * Initialize a new Builder to construct an {@link AppUriAuthenticationPolicy}.
+         */
+        public Builder() {
+            mPackageNameToUris = new HashMap<>();
+        }
+
+        /**
+         * Adds mappings from an app and URI to an alias, which will be used for authentication.
+         * <p>
+         * If this method is called with a package name and URI that was previously added, the
+         * previous alias will be overwritten.
+         *
+         * @param appPackageName The app's package name to authenticate the user to.
+         * @param uri            The URI to authenticate the user to.
+         * @param alias          The alias which will be used for authentication.
+         *
+         * @return the same Builder instance.
+         */
+        @NonNull
+        public Builder addAppAndUriMapping(@NonNull String appPackageName, @NonNull Uri uri,
+                @NonNull String alias) {
+            Objects.requireNonNull(appPackageName);
+            Objects.requireNonNull(uri);
+            Objects.requireNonNull(alias);
+            UrisToAliases urisToAliases =
+                    mPackageNameToUris.getOrDefault(appPackageName, new UrisToAliases());
+            urisToAliases.addUriToAlias(uri, alias);
+            mPackageNameToUris.put(appPackageName, urisToAliases);
+            return this;
+        }
+
+        /**
+         * Adds mappings from an app and list of URIs to a list of aliases, which will be used for
+         * authentication.
+         * <p>
+         * appPackageName -> uri -> alias
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder addAppAndUriMapping(@NonNull String appPackageName,
+                @NonNull UrisToAliases urisToAliases) {
+            Objects.requireNonNull(appPackageName);
+            Objects.requireNonNull(urisToAliases);
+            mPackageNameToUris.put(appPackageName, urisToAliases);
+            return this;
+        }
+
+        /**
+         * Combines all of the attributes that have been set on the {@link Builder}
+         *
+         * @return a new {@link AppUriAuthenticationPolicy} object.
+         */
+        @NonNull
+        public AppUriAuthenticationPolicy build() {
+            return new AppUriAuthenticationPolicy(mPackageNameToUris);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeMap(mAppToUris);
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<AppUriAuthenticationPolicy> CREATOR =
+            new Parcelable.Creator<AppUriAuthenticationPolicy>() {
+                @Override
+                public AppUriAuthenticationPolicy createFromParcel(Parcel in) {
+                    Map<String, UrisToAliases> appToUris = new HashMap<>();
+                    in.readMap(appToUris, UrisToAliases.class.getClassLoader());
+                    return new AppUriAuthenticationPolicy(appToUris);
+                }
+
+                @Override
+                public AppUriAuthenticationPolicy[] newArray(int size) {
+                    return new AppUriAuthenticationPolicy[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return "AppUriAuthenticationPolicy{"
+                + "mPackageNameToUris=" + mAppToUris
+                + '}';
+    }
+
+    /**
+     * Return the authentication policy mapping, which determines which alias for a private key
+     * and certificate pair should be used for authentication.
+     * <p>
+     * appPackageName -> uri -> alias
+     */
+    @NonNull
+    public Map<String, Map<Uri, String>> getAppAndUriMappings() {
+        Map<String, Map<Uri, String>> appAndUris = new HashMap<>();
+        for (Map.Entry<String, UrisToAliases> entry : mAppToUris.entrySet()) {
+            appAndUris.put(entry.getKey(), entry.getValue().getUrisToAliases());
+        }
+        return appAndUris;
+    }
+
+    /**
+     * Restore a previously saved {@link AppUriAuthenticationPolicy} from XML.
+     *
+     * @hide
+     */
+    @Nullable
+    public static AppUriAuthenticationPolicy readFromXml(@NonNull XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        AppUriAuthenticationPolicy.Builder builder = new AppUriAuthenticationPolicy.Builder();
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_APP_TO_URIS)) {
+                continue;
+            }
+            String app = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_APP);
+            UrisToAliases urisToAliases = UrisToAliases.readFromXml(parser);
+            builder.addAppAndUriMapping(app, urisToAliases);
+        }
+        return builder.build();
+    }
+
+    /**
+     * Save the {@link AppUriAuthenticationPolicy} to XML.
+     *
+     * @hide
+     */
+    public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+        for (Map.Entry<String, UrisToAliases> appsToUris : mAppToUris.entrySet()) {
+            out.startTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+            out.attribute(null, KEY_AUTHENTICATION_POLICY_APP, appsToUris.getKey());
+            appsToUris.getValue().writeToXml(out);
+            out.endTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+        }
+    }
+
+    /**
+     * Get the set of aliases found in the policy.
+     *
+     * @hide
+     */
+    public Set<String> getAliases() {
+        Set<String> aliases = new HashSet<>();
+        for (UrisToAliases appsToUris : mAppToUris.values()) {
+            aliases.addAll(appsToUris.getUrisToAliases().values());
+        }
+        return aliases;
+    }
+
+}
diff --git a/keystore/java/android/security/CredentialManagementApp.java b/keystore/java/android/security/CredentialManagementApp.java
new file mode 100644
index 0000000..cbb2301
--- /dev/null
+++ b/keystore/java/android/security/CredentialManagementApp.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * The credential management app has the ability to manage the user's KeyChain credentials on
+ * unmanaged devices. {@link KeyChain#createManageCredentialsIntent} should be used by an app to
+ * request to become the credential management app. The user must approve this request before the
+ * app can manage the user's credentials.
+ * <p>
+ * Note: there can only be one credential management on the device. If another app requests to
+ * become the credential management app and the user approves, then the existing credential
+ * management app will no longer be able to manage credentials.
+ * <p>
+ * The requesting credential management app should include its authentication policy in the
+ * requesting intent. The authentication policy declares which certificates should be used for a
+ * given list of apps and URIs.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public class CredentialManagementApp {
+
+    private static final String TAG = "CredentialManagementApp";
+    private static final String KEY_PACKAGE_NAME = "package_name";
+
+    /**
+     * The credential management app's package name
+     */
+    @NonNull
+    private final String mPackageName;
+
+    /**
+     * The mappings from an app and list of URIs to a list of aliases, which will be used for
+     * authentication.
+     * <p>
+     * appPackageName -> uri -> alias
+     */
+    @NonNull
+    private AppUriAuthenticationPolicy mAuthenticationPolicy;
+
+    public CredentialManagementApp(@NonNull String packageName,
+            @NonNull AppUriAuthenticationPolicy authenticationPolicy) {
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(authenticationPolicy);
+        mPackageName = packageName;
+        mAuthenticationPolicy = authenticationPolicy;
+    }
+
+    /**
+     * Returns the package name of the credential management app.
+     */
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Returns the authentication policy of the credential management app.
+     */
+    @NonNull
+    public AppUriAuthenticationPolicy getAuthenticationPolicy() {
+        return mAuthenticationPolicy;
+    }
+
+    /**
+     * Sets the authentication policy of the credential management app.
+     */
+    public void setAuthenticationPolicy(@Nullable AppUriAuthenticationPolicy authenticationPolicy) {
+        Objects.requireNonNull(authenticationPolicy);
+        mAuthenticationPolicy = authenticationPolicy;
+    }
+
+    /**
+     * Restore a previously saved {@link CredentialManagementApp} from XML.
+     */
+    @Nullable
+    public static CredentialManagementApp readFromXml(@NonNull XmlPullParser parser) {
+        try {
+            String packageName = parser.getAttributeValue(null, KEY_PACKAGE_NAME);
+            AppUriAuthenticationPolicy policy = AppUriAuthenticationPolicy.readFromXml(parser);
+            return new CredentialManagementApp(packageName, policy);
+        } catch (XmlPullParserException | IOException e) {
+            Log.w(TAG, "Reading from xml failed", e);
+        }
+        return null;
+    }
+
+    /**
+     * Save the {@link CredentialManagementApp} to XML.
+     */
+    public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+        out.attribute(null, KEY_PACKAGE_NAME, mPackageName);
+        if (mAuthenticationPolicy != null) {
+            mAuthenticationPolicy.writeToXml(out);
+        }
+    }
+}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 7abcfdc..f41b608 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -49,6 +49,8 @@
 
     public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER";
 
+    public static final String ACTION_MANAGE_CREDENTIALS = "android.security.MANAGE_CREDENTIALS";
+
     /**
      * Key prefix for CA certificates.
      *
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 97da3cc..add52fa 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -18,6 +18,8 @@
 import android.content.pm.StringParceledListSlice;
 import android.security.keymaster.KeymasterCertificateChain;
 import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.security.AppUriAuthenticationPolicy;
+import android.net.Uri;
 
 /**
  * Caller is required to ensure that {@link KeyStore#unlock
@@ -46,6 +48,7 @@
     boolean installKeyPair(
         in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
     boolean removeKeyPair(String alias);
+    boolean containsKeyPair(String alias);
 
     // APIs used by Settings
     boolean deleteCaCertificate(String alias);
@@ -55,6 +58,13 @@
     boolean containsCaAlias(String alias);
     byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
     List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
+    void setCredentialManagementApp(String packageName, in AppUriAuthenticationPolicy policy);
+    void updateCredentialManagementAppPolicy(in AppUriAuthenticationPolicy policy);
+    boolean hasCredentialManagementApp();
+    String getCredentialManagementAppPackageName();
+    AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
+    String getPredefinedAliasForPackageAndUri(String packageName, in Uri uri);
+    void removeCredentialManagementApp();
 
     // APIs used by KeyChainActivity
     void setGrant(int uid, String alias, boolean value);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index a77aec2..c6e72b0 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -15,6 +15,8 @@
  */
 package android.security;
 
+import static android.security.Credentials.ACTION_MANAGE_CREDENTIALS;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -122,6 +124,11 @@
     private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
 
     /**
+     * Package name for Settings.
+     */
+    private static final String SETTINGS_PACKAGE = "com.android.settings";
+
+    /**
      * Extra for use with {@link #ACTION_CHOOSER}
      * @hide Also used by KeyChainActivity implementation
      */
@@ -202,6 +209,20 @@
     public static final String EXTRA_PKCS12 = "PKCS12";
 
     /**
+     * Extra used by {@link #createManageCredentialsIntent(AppUriAuthenticationPolicy)} to specify
+     * the authentication policy of the credential management app.
+     *
+     * <p>The authentication policy declares which alias for a private key and certificate pair
+     * should be used for authentication, given a list of apps and URIs.
+     *
+     * <p>The extra value should be a {@link AppUriAuthenticationPolicy}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_AUTHENTICATION_POLICY =
+            "android.security.extra.AUTHENTICATION_POLICY";
+
+    /**
      * Broadcast Action: Indicates the trusted storage has changed. Sent when
      * one of this happens:
      *
@@ -386,6 +407,23 @@
     }
 
     /**
+     * Returns an {@code Intent} that should be used by an app to request to manage the user's
+     * credentials. This is limited to unmanaged devices. The authentication policy must be
+     * provided to be able to make this request successfully.
+     *
+     * @param policy The authentication policy determines which alias for a private key and
+     *               certificate pair should be used for authentication.
+     */
+    @NonNull
+    public static Intent createManageCredentialsIntent(@NonNull AppUriAuthenticationPolicy policy) {
+        Intent intent = new Intent(ACTION_MANAGE_CREDENTIALS);
+        intent.setComponent(ComponentName.createRelative(SETTINGS_PACKAGE,
+                ".security.RequestManageCredentials"));
+        intent.putExtra(EXTRA_AUTHENTICATION_POLICY, policy);
+        return intent;
+    }
+
+    /**
      * Launches an {@code Activity} for the user to select the alias
      * for a private key and certificate pair for authentication. The
      * selected alias or null will be returned via the
diff --git a/keystore/java/android/security/UrisToAliases.java b/keystore/java/android/security/UrisToAliases.java
new file mode 100644
index 0000000..65d433a
--- /dev/null
+++ b/keystore/java/android/security/UrisToAliases.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The mapping from URI to alias, which determines the alias to use when the user visits a URI.
+ * This mapping is part of the {@link AppUriAuthenticationPolicy}, which specifies which app this
+ * mapping should be used for.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public final class UrisToAliases implements Parcelable {
+
+    private static final String KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS =
+            "authentication_policy_uri_to_alias";
+    private static final String KEY_AUTHENTICATION_POLICY_URI = "policy_uri";
+    private static final String KEY_AUTHENTICATION_POLICY_ALIAS = "policy_alias";
+
+    /**
+     * The mappings from URIs to aliases, which will be used for authentication.
+     */
+    @NonNull
+    private final Map<Uri, String> mUrisToAliases;
+
+    public UrisToAliases() {
+        this.mUrisToAliases = new HashMap<>();
+    }
+
+    private UrisToAliases(@NonNull Map<Uri, String> urisToAliases) {
+        this.mUrisToAliases = urisToAliases;
+    }
+
+    @NonNull
+    public static final Creator<UrisToAliases> CREATOR = new Creator<UrisToAliases>() {
+        @Override
+        public UrisToAliases createFromParcel(Parcel in) {
+            Map<Uri, String> urisToAliases = new HashMap<>();
+            in.readMap(urisToAliases, String.class.getClassLoader());
+            return new UrisToAliases(urisToAliases);
+        }
+
+        @Override
+        public UrisToAliases[] newArray(int size) {
+            return new UrisToAliases[size];
+        }
+    };
+
+    /**
+     * Returns the mapping from URIs to aliases.
+     */
+    @NonNull
+    public Map<Uri, String> getUrisToAliases() {
+        return Collections.unmodifiableMap(mUrisToAliases);
+    }
+
+    /**
+     * Adds mapping from an URI to an alias.
+     */
+    public void addUriToAlias(@NonNull Uri uri, @NonNull String alias) {
+        mUrisToAliases.put(uri, alias);
+    }
+
+    /**
+     * Restore a previously saved {@link UrisToAliases} from XML.
+     */
+    @Nullable
+    public static UrisToAliases readFromXml(@NonNull XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        Map<Uri, String> urisToAliases = new HashMap<>();
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS)) {
+                continue;
+            }
+            Uri uri = Uri.parse(parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_URI));
+            String alias = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_ALIAS);
+            urisToAliases.put(uri, alias);
+        }
+        return new UrisToAliases(urisToAliases);
+    }
+
+    /**
+     * Save the {@link UrisToAliases} to XML.
+     */
+    public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+        for (Map.Entry<Uri, String> urisToAliases : mUrisToAliases.entrySet()) {
+            out.startTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+            out.attribute(null, KEY_AUTHENTICATION_POLICY_URI, urisToAliases.getKey().toString());
+            out.attribute(null, KEY_AUTHENTICATION_POLICY_ALIAS, urisToAliases.getValue());
+            out.endTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeMap(mUrisToAliases);
+    }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 5867ef6..b1b6306 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -83,8 +83,7 @@
         boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY));
 
         // java.security.KeyStore
-        put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
-        put("Alg.Alias.KeyStore.AndroidKeyStoreLegacy", "AndroidKeyStore");
+        put("KeyStore." + providerName, PACKAGE_NAME + ".AndroidKeyStoreSpi");
 
         // java.security.KeyPairGenerator
         put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
index 388eb28..120039d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
@@ -116,7 +116,7 @@
     }
 
     @Override
-    public void onTransitionReady(@NonNull IBinder transitionToken, TransitionInfo info,
+    public void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction t) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
                 transitionToken, info);
@@ -131,22 +131,53 @@
                         + transitionToken);
             }
             mActiveTransitions.put(transitionToken, new ArrayList<>());
-            for (int i = 0; i < info.getChanges().size(); ++i) {
-                final SurfaceControl leash = info.getChanges().get(i).getLeash();
+            boolean isOpening = isOpeningType(info.getType());
+            if (info.getRootLeash().isValid()) {
+                t.show(info.getRootLeash());
+            }
+            // changes should be ordered top-to-bottom in z
+            for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+                final TransitionInfo.Change change = info.getChanges().get(i);
+                final SurfaceControl leash = change.getLeash();
                 final int mode = info.getChanges().get(i).getMode();
+
+                // Don't animate anything with an animating parent
+                if (change.getParent() != null) {
+                    if (mode == TRANSIT_OPEN || mode == TRANSIT_SHOW) {
+                        t.show(leash);
+                        t.setMatrix(leash, 1, 0, 0, 1);
+                    }
+                    continue;
+                }
+
+                t.reparent(leash, info.getRootLeash());
+                t.setPosition(leash, change.getEndAbsBounds().left - info.getRootOffset().x,
+                        change.getEndAbsBounds().top - info.getRootOffset().y);
+                // Put all the OPEN/SHOW on top
                 if (mode == TRANSIT_OPEN || mode == TRANSIT_SHOW) {
                     t.show(leash);
                     t.setMatrix(leash, 1, 0, 0, 1);
-                    if (isOpeningType(info.getType())) {
+                    if (isOpening) {
+                        // put on top and fade in
+                        t.setLayer(leash, info.getChanges().size() - i);
                         t.setAlpha(leash, 0.f);
                         startExampleAnimation(transitionToken, leash, true /* show */);
                     } else {
+                        // put on bottom and leave it visible without fade
+                        t.setLayer(leash, -i);
                         t.setAlpha(leash, 1.f);
                     }
                 } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_HIDE) {
-                    if (!isOpeningType(info.getType())) {
+                    if (isOpening) {
+                        // put on bottom and leave visible without fade
+                        t.setLayer(leash, -i);
+                    } else {
+                        // put on top and fade out
+                        t.setLayer(leash, info.getChanges().size() - i);
                         startExampleAnimation(transitionToken, leash, false /* show */);
                     }
+                } else {
+                    t.setLayer(leash, info.getChanges().size() - i);
                 }
             }
             t.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index f199072..d3032f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -136,13 +136,6 @@
         mAppPairLayout = null;
     }
 
-    void setVisible(boolean visible) {
-        if (mAppPairLayout == null) {
-            return;
-        }
-        mAppPairLayout.setDividerVisibility(visible);
-    }
-
     @Override
     public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
         if (mRootTaskInfo == null || taskInfo.taskId == mRootTaskInfo.taskId) {
@@ -160,32 +153,41 @@
 
         if (mTaskLeash1 == null || mTaskLeash2 == null) return;
 
-        setVisible(true);
+        mAppPairLayout.init();
         final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
         final Rect dividerBounds = mAppPairLayout.getDividerBounds();
 
         // TODO: Is there more we need to do here?
-        mSyncQueue.runInSync(t -> t
-                .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
-                        mTaskInfo1.positionInParent.y)
-                .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
-                        mTaskInfo2.positionInParent.y)
-                .setLayer(dividerLeash, Integer.MAX_VALUE)
-                .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
-                .show(mRootTaskLeash)
-                .show(dividerLeash)
-                .show(mTaskLeash1)
-                .show(mTaskLeash2));
+        mSyncQueue.runInSync(t -> {
+            t.setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
+                    mTaskInfo1.positionInParent.y)
+                    .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
+                            mTaskInfo2.positionInParent.y)
+                    .setLayer(dividerLeash, Integer.MAX_VALUE)
+                    .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+                    .show(mRootTaskLeash)
+                    .show(mTaskLeash1)
+                    .show(mTaskLeash2);
+        });
     }
 
     @Override
     public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
         if (taskInfo.taskId == getRootTaskId()) {
+            if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
+                mSyncQueue.runInSync(t -> {
+                    if (taskInfo.isVisible) {
+                        t.show(mRootTaskLeash);
+                    } else {
+                        t.hide(mRootTaskLeash);
+                    }
+                });
+            }
             mRootTaskInfo = taskInfo;
 
             if (mAppPairLayout != null
                     && mAppPairLayout.updateConfiguration(mRootTaskInfo.configuration)) {
-                // Update bounds when there is root bounds or orientation changed.
+                // Update bounds when root bounds or its orientation changed.
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
                 final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
                 final Rect dividerBounds = mAppPairLayout.getDividerBounds();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
index f8703f7..8c8655e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.apppairs;
 
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
@@ -45,21 +44,18 @@
 /**
  * Records and handles layout of a pair of apps.
  */
-// TODO(172704238): add tests
 final class AppPairLayout {
     private static final String DIVIDER_WINDOW_TITLE = "AppPairDivider";
-    private final Context mContext;
-    private final AppPairWindowManager mAppPairWindowManager;
-    private final SurfaceControlViewHost mViewHost;
-
+    private final Display mDisplay;
     private final int mDividerWindowWidth;
     private final int mDividerWindowInsets;
+    private final AppPairWindowManager mAppPairWindowManager;
 
-    private boolean mIsLandscape;
+    private Context mContext;
     private Rect mRootBounds;
     private DIVIDE_POLICY mDividePolicy;
 
-    private DividerView mDividerView;
+    private SurfaceControlViewHost mViewHost;
     private SurfaceControl mDividerLeash;
 
     AppPairLayout(
@@ -68,7 +64,7 @@
             Configuration configuration,
             SurfaceControl rootLeash) {
         mContext = context.createConfigurationContext(configuration);
-        mIsLandscape = isLandscape(configuration);
+        mDisplay = display;
         mRootBounds = configuration.windowConfiguration.getBounds();
         mDividerWindowWidth = mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_divider_thickness);
@@ -76,26 +72,22 @@
                 com.android.internal.R.dimen.docked_stack_divider_insets);
 
         mAppPairWindowManager = new AppPairWindowManager(configuration, rootLeash);
-        mViewHost = new SurfaceControlViewHost(mContext, display, mAppPairWindowManager);
         mDividePolicy = DIVIDE_POLICY.MIDDLE;
-        mDividePolicy.update(mIsLandscape, mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
+        mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
     }
 
     boolean updateConfiguration(Configuration configuration) {
         mAppPairWindowManager.setConfiguration(configuration);
         final Rect rootBounds = configuration.windowConfiguration.getBounds();
-        final boolean isLandscape = isLandscape(configuration);
-        if (mIsLandscape == isLandscape && isIdenticalBounds(mRootBounds, rootBounds)) {
+        if (isIdenticalBounds(mRootBounds, rootBounds)) {
             return false;
         }
 
-        mIsLandscape = isLandscape;
+        mContext = mContext.createConfigurationContext(configuration);
         mRootBounds = rootBounds;
-        mDividePolicy.update(mIsLandscape, mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
-        mViewHost.relayout(
-                mDividePolicy.mDividerBounds.width(),
-                mDividePolicy.mDividerBounds.height());
-        // TODO(172704238): handle divider bar rotation.
+        mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
+        release();
+        init();
         return true;
     }
 
@@ -116,22 +108,19 @@
     }
 
     void release() {
-        if (mViewHost == null) return;
+        if (mViewHost == null) {
+            return;
+        }
         mViewHost.release();
+        mDividerLeash = null;
+        mViewHost = null;
     }
 
-    void setDividerVisibility(boolean visible) {
-        if (mDividerView == null) {
-            initDivider();
+    void init() {
+        if (mViewHost == null) {
+            mViewHost = new SurfaceControlViewHost(mContext, mDisplay, mAppPairWindowManager);
         }
-        if (visible) {
-            mDividerView.show();
-        } else {
-            mDividerView.hide();
-        }
-    }
 
-    private void initDivider() {
         final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
                 .inflate(R.layout.split_divider, null);
 
@@ -147,14 +136,9 @@
         lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
 
         mViewHost.setView(dividerView, lp);
-        mDividerView = dividerView;
         mDividerLeash = mAppPairWindowManager.getSurfaceControl(mViewHost.getWindowToken());
     }
 
-    private static boolean isLandscape(Configuration configuration) {
-        return configuration.orientation == ORIENTATION_LANDSCAPE;
-    }
-
     private static boolean isIdenticalBounds(Rect bounds1, Rect bounds2) {
         return bounds1.left == bounds2.left && bounds1.top == bounds2.top
                 && bounds1.right == bounds2.right && bounds1.bottom == bounds2.bottom;
@@ -167,8 +151,7 @@
     enum DIVIDE_POLICY {
         MIDDLE;
 
-        void update(boolean isLandscape, Rect rootBounds, int dividerWindowWidth,
-                int dividerWindowInsets) {
+        void update(Rect rootBounds, int dividerWindowWidth, int dividerWindowInsets) {
             final int dividerOffset = dividerWindowWidth / 2;
             final int boundsOffset = dividerOffset - dividerWindowInsets;
 
@@ -179,7 +162,7 @@
             switch (this) {
                 case MIDDLE:
                 default:
-                    if (isLandscape) {
+                    if (isLandscape(rootBounds)) {
                         mDividerBounds.left = rootBounds.width() / 2 - dividerOffset;
                         mDividerBounds.right = rootBounds.width() / 2 + dividerOffset;
                         mBounds1.left = rootBounds.width() / 2 + boundsOffset;
@@ -193,6 +176,10 @@
             }
         }
 
+        private boolean isLandscape(Rect bounds) {
+            return bounds.width() > bounds.height();
+        }
+
         Rect mDividerBounds;
         Rect mBounds1;
         Rect mBounds2;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
index af06764..ef3e3e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
@@ -36,6 +36,4 @@
     void dump(@NonNull PrintWriter pw, String prefix);
     /** Called when the shell organizer has been registered. */
     void onOrganizerRegistered();
-    /** Called when the visibility of the keyguard changes. */
-    void onKeyguardVisibilityChanged(boolean showing);
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
index 925a4f3..f2f0982 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
@@ -16,8 +16,6 @@
 
 package com.android.wm.shell.apppairs;
 
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
 
 import android.app.ActivityManager;
@@ -30,15 +28,13 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerCallback;
-import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import java.io.PrintWriter;
 
 /**
  * Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
  */
-public class AppPairsController implements AppPairs, TaskStackListenerCallback {
+public class AppPairsController implements AppPairs {
     private static final String TAG = AppPairsController.class.getSimpleName();
 
     private final ShellTaskOrganizer mTaskOrganizer;
@@ -48,14 +44,12 @@
     // Active app-pairs mapped by root task id key.
     private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
     private final DisplayController mDisplayController;
-    private int mForegroundTaskId = INVALID_TASK_ID;
 
     public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
-                DisplayController displayController, TaskStackListenerImpl taskStackListener) {
+                DisplayController displayController) {
         mTaskOrganizer = organizer;
         mSyncQueue = syncQueue;
         mDisplayController = displayController;
-        taskStackListener.addListener(this);
     }
 
     @Override
@@ -71,27 +65,6 @@
     }
 
     @Override
-    public void onTaskMovedToFront(int taskId) {
-        mForegroundTaskId = INVALID_TASK_ID;
-        for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
-            final AppPair candidate = mActiveAppPairs.valueAt(i);
-            final boolean containForegroundTask = candidate.contains(taskId);
-            candidate.setVisible(containForegroundTask);
-            if (containForegroundTask) {
-                mForegroundTaskId = candidate.getRootTaskId();
-            }
-        }
-    }
-
-    @Override
-    public void onKeyguardVisibilityChanged(boolean showing) {
-        if (mForegroundTaskId == INVALID_TASK_ID) {
-            return;
-        }
-        mActiveAppPairs.get(mForegroundTaskId).setVisible(!showing);
-    }
-
-    @Override
     public boolean pair(int taskId1, int taskId2) {
         final ActivityManager.RunningTaskInfo task1 = mTaskOrganizer.getRunningTaskInfo(taskId1);
         final ActivityManager.RunningTaskInfo task2 = mTaskOrganizer.getRunningTaskInfo(taskId2);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 8a547b4..7b3b5db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -18,12 +18,10 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
 import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
 import static android.content.Intent.EXTRA_PACKAGE_NAME;
@@ -78,7 +76,7 @@
     private static final String TAG = DragAndDropPolicy.class.getSimpleName();
 
     private final Context mContext;
-    private final IActivityTaskManager mIActivityTaskManager;
+    private final ActivityTaskManager mActivityTaskManager;
     private final Starter mStarter;
     private final SplitScreen mSplitScreen;
     private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
@@ -86,15 +84,15 @@
     private DragSession mSession;
 
     public DragAndDropPolicy(Context context, SplitScreen splitScreen) {
-        this(context, ActivityTaskManager.getService(), splitScreen,
+        this(context, ActivityTaskManager.getInstance(), splitScreen,
                 new DefaultStarter(context, splitScreen));
     }
 
     @VisibleForTesting
-    DragAndDropPolicy(Context context, IActivityTaskManager activityTaskManager,
+    DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
             SplitScreen splitScreen, Starter starter) {
         mContext = context;
-        mIActivityTaskManager = activityTaskManager;
+        mActivityTaskManager = activityTaskManager;
         mSplitScreen = splitScreen;
         mStarter = starter;
     }
@@ -103,7 +101,7 @@
      * Starts a new drag session with the given initial drag data.
      */
     void start(DisplayLayout displayLayout, ClipData data) {
-        mSession = new DragSession(mContext, mIActivityTaskManager, displayLayout, data);
+        mSession = new DragSession(mContext, mActivityTaskManager, displayLayout, data);
         // TODO(b/169894807): Also update the session data with task stack changes
         mSession.update();
     }
@@ -271,7 +269,7 @@
      */
     private static class DragSession {
         private final Context mContext;
-        private final IActivityTaskManager mIActivityTaskManager;
+        private final ActivityTaskManager mActivityTaskManager;
         private final ClipData mInitialDragData;
 
         final DisplayLayout displayLayout;
@@ -285,10 +283,10 @@
         boolean dragItemSupportsSplitscreen;
         boolean isPhone;
 
-        DragSession(Context context, IActivityTaskManager activityTaskManager,
+        DragSession(Context context, ActivityTaskManager activityTaskManager,
                 DisplayLayout dispLayout, ClipData data) {
             mContext = context;
-            mIActivityTaskManager = activityTaskManager;
+            mActivityTaskManager = activityTaskManager;
             mInitialDragData = data;
             displayLayout = dispLayout;
         }
@@ -298,19 +296,14 @@
          */
         void update() {
 
-            try {
-                List<ActivityManager.RunningTaskInfo> tasks =
-                        mIActivityTaskManager.getFilteredTasks(1,
-                                false /* filterOnlyVisibleRecents */);
-                if (!tasks.isEmpty()) {
-                    final ActivityManager.RunningTaskInfo task = tasks.get(0);
-                    runningTaskWinMode = task.getWindowingMode();
-                    runningTaskActType = task.getActivityType();
-                    runningTaskId = task.taskId;
-                    runningTaskIsResizeable = task.isResizeable;
-                }
-            } catch (RemoteException e) {
-                // Fall through
+            List<ActivityManager.RunningTaskInfo> tasks =
+                    mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
+            if (!tasks.isEmpty()) {
+                final ActivityManager.RunningTaskInfo task = tasks.get(0);
+                runningTaskWinMode = task.getWindowingMode();
+                runningTaskActType = task.getActivityType();
+                runningTaskId = task.taskId;
+                runningTaskIsResizeable = task.isResizeable;
             }
 
             final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
index 090d227..4e62ea6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -272,8 +272,9 @@
     @VisibleForTesting
     void applyBoundsAndOffsets(WindowContainerToken token, SurfaceControl leash,
             WindowContainerTransaction wct, SurfaceControl.Transaction t) {
-        wct.setBounds(token, mCurrentDisplayBounds.isEmpty() ? null : mCurrentDisplayBounds);
+        wct.setBounds(token, mCurrentDisplayBounds);
         t.setPosition(leash, mOffsetX,  mOffsetY);
+        t.setWindowCrop(leash, mCurrentDisplayBounds.width(), mCurrentDisplayBounds.height());
     }
 
     @VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java
index 061d3f8..6e87f13 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java
@@ -107,6 +107,7 @@
         transaction.setWindowCrop(leash, crop);
     }
 
+    // TODO(b/173440321): Correct presentation of letterboxed activities in One-handed mode.
     private void resolveTaskPositionAndCrop(
                 ActivityManager.RunningTaskInfo taskInfo,
                 Point positionInParent,
@@ -125,15 +126,18 @@
         final Rect activityBounds = taskInfo.letterboxActivityBounds;
 
         Insets insets = getInsets();
+        Rect displayBoundsWithInsets =
+                new Rect(mWindowManager.getMaximumWindowMetrics().getBounds());
+        displayBoundsWithInsets.inset(insets);
 
         Rect taskBoundsWithInsets = new Rect(taskBounds);
-        applyInsets(taskBoundsWithInsets, insets, taskInfo.parentBounds);
+        taskBoundsWithInsets.intersect(displayBoundsWithInsets);
 
         Rect activityBoundsWithInsets = new Rect(activityBounds);
-        applyInsets(activityBoundsWithInsets, insets, taskInfo.parentBounds);
+        activityBoundsWithInsets.intersect(displayBoundsWithInsets);
 
         Rect parentBoundsWithInsets = new Rect(parentBounds);
-        applyInsets(parentBoundsWithInsets, insets, parentBounds);
+        parentBoundsWithInsets.intersect(displayBoundsWithInsets);
 
         // Crop need to be in the task coordinates.
         crop.set(activityBoundsWithInsets);
@@ -217,10 +221,4 @@
                                 | WindowInsets.Type.displayCutout());
     }
 
-    private void applyInsets(Rect innerBounds, Insets insets, Rect outerBounds) {
-        Rect outerBoundsWithInsets = new Rect(outerBounds);
-        outerBoundsWithInsets.inset(insets);
-        innerBounds.intersect(outerBoundsWithInsets);
-    }
-
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
index 1d54300..d421755 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
@@ -239,7 +239,9 @@
                     + " callers=\n" + Debug.getCallers(5, "    "));
         }
 
-        maybeCreateSyncApplier();
+        if (!maybeCreateSyncApplier()) {
+            return;
+        }
 
         mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
                 showResizeHandle);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 07af289..6d6c761 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -506,7 +506,7 @@
 
             // Try fetching the top running task.
             final List<RunningTaskInfo> runningTasks =
-                    ActivityTaskManager.getService().getTasks(1 /* maxNum */);
+                    ActivityTaskManager.getInstance().getTasks(1 /* maxNum */);
             if (runningTasks == null || runningTasks.isEmpty()) {
                 return false;
             }
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index d7afa0e..4a498d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -29,7 +29,11 @@
         "truth-prebuilt",
         "app-helpers-core",
         "launcher-helper-lib",
-        "launcher-aosp-tapl"
+        "launcher-aosp-tapl",
+        "wm-flicker-common-assertions",
+        "wm-flicker-common-app-helpers",
+        "platform-test-annotations",
+        "wmshell-flicker-test-components",
     ],
 }
 
@@ -47,6 +51,10 @@
         "truth-prebuilt",
         "app-helpers-core",
         "launcher-helper-lib",
-        "launcher-aosp-tapl"
+        "launcher-aosp-tapl",
+        "wm-flicker-common-assertions",
+        "wm-flicker-common-app-helpers",
+        "platform-test-annotations",
+        "wmshell-flicker-test-components",
     ],
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
index 9e83309..101b5bf 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -36,6 +36,8 @@
     <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
     <!-- Control test app's media session -->
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
+    <!-- ATM.removeRootTasksWithActivityTypes() -->
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
     <application>
         <uses-library android:name="android.test.runner"/>
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index 3c222e7..96234fc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -16,31 +16,24 @@
 
 package com.android.wm.shell.flicker
 
-import android.content.ComponentName
-
 const val IME_WINDOW_NAME = "InputMethod"
-const val PIP_WINDOW_NAME = "PipMenuActivity"
-const val SPLITSCREEN_PRIMARY_WINDOW_NAME = "SplitScreenActivity"
-const val SPLITSCREEN_SECONDARY_WINDOW_NAME = "SplitScreenSecondaryActivity"
+const val PIP_MENU_WINDOW_NAME = "PipMenuActivity"
 
 const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
 const val TEST_APP_PACKAGE_NAME = "com.android.wm.shell.flicker.testapp"
 
 // Test App > Pip Activity
-val TEST_APP_PIP_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
-        TEST_APP_PACKAGE_NAME, ".PipActivity")
 const val TEST_APP_PIP_ACTIVITY_LABEL = "PipApp"
-const val TEST_APP_PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
+const val TEST_APP_PIP_MENU_ACTION_NO_OP = "No-Op"
+const val TEST_APP_PIP_MENU_ACTION_ON = "On"
+const val TEST_APP_PIP_MENU_ACTION_OFF = "Off"
+const val TEST_APP_PIP_MENU_ACTION_CLEAR = "Clear"
 
 // Test App > Ime Activity
-val TEST_APP_IME_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
-        TEST_APP_PACKAGE_NAME, ".ImeActivity")
 const val TEST_APP_IME_ACTIVITY_LABEL = "ImeApp"
+// Test App > Test Activity
+const val TEST_APP_FIXED_ACTIVITY_LABEL = "FixedApp"
 
 // Test App > SplitScreen Activity
-val TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
-        TEST_APP_PACKAGE_NAME, ".$SPLITSCREEN_PRIMARY_WINDOW_NAME")
-val TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
-        TEST_APP_PACKAGE_NAME, ".$SPLITSCREEN_SECONDARY_WINDOW_NAME")
 const val TEST_APP_SPLITSCREEN_PRIMARY_LABEL = "SplitScreenPrimaryApp"
 const val TEST_APP_SPLITSCREEN_SECONDARY_LABEL = "SplitScreenSecondaryApp"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
index 2fc6944..ced99de 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.apppairs
 
+import android.platform.test.annotations.Presubmit
 import android.os.SystemClock
 import android.util.Log
 import android.view.Surface
@@ -43,6 +44,7 @@
  * Test AppPairs launch.
  * To run this test: `atest WMShellFlickerTests:AppPairsTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt
index 1a4de0a..f32cd88 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt
@@ -17,12 +17,11 @@
 package com.android.wm.shell.flicker.apppairs
 
 import com.android.wm.shell.flicker.NonRotationTestBase
-import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME
 import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL
-import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME
 import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_LABEL
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import com.android.wm.shell.flicker.testapp.Components
 
 abstract class AppPairsTestBase(
     rotationName: String,
@@ -30,11 +29,11 @@
 ) : NonRotationTestBase(rotationName, rotation) {
     protected val appPairsHelper = AppPairsHelper(instrumentation,
             TEST_APP_SPLITSCREEN_PRIMARY_LABEL,
-            TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME)
+            Components.SplitScreenActivity())
     protected val primaryApp = SplitScreenHelper(instrumentation,
             TEST_APP_SPLITSCREEN_PRIMARY_LABEL,
-            TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME)
+            Components.SplitScreenActivity())
     protected val secondaryApp = SplitScreenHelper(instrumentation,
             TEST_APP_SPLITSCREEN_SECONDARY_LABEL,
-            TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME)
+            Components.SplitScreenSecondaryActivity())
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
index 3b6fcdb..e2cda7a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
@@ -17,19 +17,19 @@
 package com.android.wm.shell.flicker.helpers
 
 import android.app.Instrumentation
-import android.content.ComponentName
 import android.graphics.Region
 import android.system.helpers.ActivityHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.wm.shell.flicker.testapp.Components
 
 class AppPairsHelper(
     instrumentation: Instrumentation,
     activityLabel: String,
-    componentName: ComponentName
+    componentsInfo: Components.ComponentsInfo
 ) : BaseAppHelper(
     instrumentation,
     activityLabel,
-    componentName
+    componentsInfo
 ) {
     val activityHelper = ActivityHelper.getInstance()
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 22496a5..6fd1df3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.helpers
 
 import android.app.Instrumentation
-import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager.FEATURE_LEANBACK
@@ -28,15 +27,15 @@
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME
+import com.android.wm.shell.flicker.testapp.Components
 
 abstract class BaseAppHelper(
     instrumentation: Instrumentation,
     launcherName: String,
-    private val launcherActivityComponent: ComponentName
+    private val componentsInfo: Components.ComponentsInfo
 ) : StandardAppHelper(
         instrumentation,
-        TEST_APP_PACKAGE_NAME,
+        Components.PACKAGE_NAME,
         launcherName,
         LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy
 ) {
@@ -53,7 +52,7 @@
         }
 
     val defaultWindowName: String
-        get() = launcherActivityComponent.className
+        get() = componentsInfo.activityName
 
     val label: String
         get() = context.packageManager.run {
@@ -63,8 +62,12 @@
     val ui: UiObject2?
         get() = uiDevice.findObject(appSelector)
 
-    fun launchViaIntent() {
-        context.startActivity(openAppIntent)
+    fun launchViaIntent(stringExtras: Map<String, String> = mapOf()) {
+        val intent = openAppIntent
+        stringExtras.forEach() {
+            intent.putExtra(it.key, it.value)
+        }
+        context.startActivity(intent)
 
         uiDevice.wait(Until.hasObject(appSelector), APP_LAUNCH_WAIT_TIME_MS)
     }
@@ -75,7 +78,7 @@
 
     override fun getOpenAppIntent(): Intent {
         val intent = Intent()
-        intent.component = launcherActivityComponent
+        intent.component = componentsInfo.componentName
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
         return intent
     }
diff --git a/core/proto/android/stats/accessibility/accessibility_enums.proto b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt
similarity index 61%
copy from core/proto/android/stats/accessibility/accessibility_enums.proto
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt
index 5118ad5..c7f19a5 100644
--- a/core/proto/android/stats/accessibility/accessibility_enums.proto
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt
@@ -14,22 +14,16 @@
  * limitations under the License.
  */
 
-syntax = "proto2";
-package android.stats.accessibility;
-option java_multiple_files = true;
+package com.android.wm.shell.flicker.helpers
 
-// The entry point of the accessibility shortcut.
-enum ShortcutType {
-  UNKNOWN_TYPE = 0;
-  A11Y_BUTTON = 1;
-  VOLUME_KEY = 2;
-  TRIPLE_TAP = 3;
-  A11Y_BUTTON_LONG_PRESS = 4;
-}
+import android.app.Instrumentation
+import com.android.wm.shell.flicker.TEST_APP_FIXED_ACTIVITY_LABEL
+import com.android.wm.shell.flicker.testapp.Components
 
-// The service status code.
-enum ServiceStatus {
-  UNKNOWN = 0;
-  ENABLED = 1;
-  DISABLED = 2;
-}
\ No newline at end of file
+class FixedAppHelper(
+    instrumentation: Instrumentation
+) : BaseAppHelper(
+        instrumentation,
+        TEST_APP_FIXED_ACTIVITY_LABEL,
+        Components.FixedActivity()
+)
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index a6650d7..d580104 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -21,8 +21,8 @@
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
 import com.android.server.wm.flicker.helpers.waitForIME
-import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
 import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL
+import com.android.wm.shell.flicker.testapp.Components
 import org.junit.Assert
 
 open class ImeAppHelper(
@@ -30,7 +30,7 @@
 ) : BaseAppHelper(
         instrumentation,
         TEST_APP_IME_ACTIVITY_LABEL,
-        TEST_APP_IME_ACTIVITY_COMPONENT_NAME
+        Components.ImeActivity()
 ) {
     fun openIME() {
         val editText = uiDevice.wait(
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 532b3de..ed5f8a4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -26,8 +26,8 @@
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.hasPipWindow
 import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
-import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
 import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_LABEL
+import com.android.wm.shell.flicker.testapp.Components
 import org.junit.Assert.assertNotNull
 import org.junit.Assert.fail
 
@@ -36,7 +36,7 @@
 ) : BaseAppHelper(
         instrumentation,
         TEST_APP_PIP_ACTIVITY_LABEL,
-        TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
+        Components.PipActivity()
 ) {
     private val mediaSessionManager: MediaSessionManager
         get() = context.getSystemService(MediaSessionManager::class.java)
@@ -70,6 +70,12 @@
         startButton.click()
     }
 
+    fun checkWithCustomActionsCheckbox() = uiDevice
+            .findObject(By.res(packageName, "with_custom_actions"))
+            ?.takeIf { it.isCheckable }
+            ?.apply { if (!isChecked) click() }
+            ?: error("'With custom actions' checkbox not found")
+
     fun pauseMedia() = mediaController?.transportControls?.pause()
             ?: error("No active media session found")
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
index 10daa67..e67fc97 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
@@ -17,19 +17,19 @@
 package com.android.wm.shell.flicker.helpers
 
 import android.app.Instrumentation
-import android.content.ComponentName
 import android.graphics.Region
 import android.os.SystemClock
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.wm.shell.flicker.testapp.Components
 
 class SplitScreenHelper(
     instrumentation: Instrumentation,
     activityLabel: String,
-    componentName: ComponentName
+    componentsInfo: Components.ComponentsInfo
 ) : BaseAppHelper(
         instrumentation,
         activityLabel,
-        componentName
+        componentsInfo
 ) {
 
     /**
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt
new file mode 100644
index 0000000..2015f49
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.app.ActivityTaskManager
+import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT
+import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS
+import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
+import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED
+import android.os.SystemClock
+import com.android.wm.shell.flicker.NonRotationTestBase
+
+abstract class AppTestBase(
+    rotationName: String,
+    rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+    companion object {
+        fun removeAllTasksButHome() {
+            val ALL_ACTIVITY_TYPE_BUT_HOME = intArrayOf(
+                    ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS,
+                    ACTIVITY_TYPE_UNDEFINED)
+            val atm = ActivityTaskManager.getService()
+            atm.removeRootTasksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME)
+        }
+
+        fun waitForAnimationComplete() {
+            // TODO: UiDevice doesn't have reliable way to wait for the completion of animation.
+            // Consider to introduce WindowManagerStateHelper to access Activity state.
+            SystemClock.sleep(1000)
+        }
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
similarity index 93%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
index 6bc9dcb..2a66074 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+package com.android.wm.shell.flicker.pip
 
 internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
new file mode 100644
index 0000000..0663eb3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.dsl.runFlicker
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.wm.shell.flicker.helpers.PipAppHelper
+import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch and exit.
+ * To run this test: `atest WMShellFlickerTests:EnterExitPipTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class EnterExitPipTest(
+    rotationName: String,
+    rotation: Int
+) : AppTestBase(rotationName, rotation) {
+    private val pipApp = PipAppHelper(instrumentation)
+    private val testApp = FixedAppHelper(instrumentation)
+
+    @Test
+    fun testDisplayMetricsPinUnpin() {
+        runFlicker(instrumentation) {
+            withTestName { "testDisplayMetricsPinUnpin" }
+            setup {
+                test {
+                    removeAllTasksButHome()
+                    device.wakeUpAndGoToHomeScreen()
+                    pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"))
+                    testApp.launchViaIntent()
+                    waitForAnimationComplete()
+                }
+            }
+            transitions {
+                // This will bring PipApp to fullscreen
+                pipApp.launchViaIntent()
+                waitForAnimationComplete()
+            }
+            teardown {
+                test {
+                    removeAllTasksButHome()
+                }
+            }
+            assertions {
+                val displayBounds = WindowUtils.getDisplayBounds(rotation)
+                windowManagerTrace {
+                    all("pipApp must remain inside visible bounds") {
+                        coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+                    }
+                    all("Initially shows both app windows then pipApp hides testApp") {
+                        showsAppWindow(testApp.defaultWindowName)
+                                .and().showsAppWindowOnTop(pipApp.defaultWindowName)
+                                .then()
+                                .hidesAppWindow(testApp.defaultWindowName)
+                    }
+                    navBarWindowIsAlwaysVisible()
+                    statusBarWindowIsAlwaysVisible()
+                }
+                layersTrace {
+                    all("Initially shows both app layers then pipApp hides testApp") {
+                        showsLayer(testApp.defaultWindowName)
+                                .and().showsLayer(pipApp.defaultWindowName)
+                                .then()
+                                .hidesLayer(testApp.defaultWindowName)
+                    }
+                    start("testApp covers the fullscreen, pipApp remains inside display") {
+                        hasVisibleRegion(testApp.defaultWindowName, displayBounds)
+                        coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
+                    }
+                    end("pipApp covers the fullscreen") {
+                        hasVisibleRegion(pipApp.defaultWindowName, displayBounds)
+                    }
+                    navBarLayerIsAlwaysVisible()
+                    statusBarLayerIsAlwaysVisible()
+                }
+            }
+        }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> {
+            val supportedRotations = intArrayOf(Surface.ROTATION_0)
+            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index a1da7c9..cb1fe4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -19,104 +19,113 @@
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.dsl.flicker
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.expandPipWindow
 import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.noUncoveredRegions
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerRotatesScales
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.PIP_WINDOW_NAME
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.wm.shell.flicker.helpers.PipAppHelper
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
 
 /**
  * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipToAppTest`
+ * To run this test: `atest WMShellFlickerTests:EnterPipTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @FlakyTest(bugId = 152738416)
 class EnterPipTest(
-    rotationName: String,
-    rotation: Int
-) : PipTestBase(rotationName, rotation) {
-    @Test
-    fun test() {
-        flicker(instrumentation) {
-            withTag { buildTestTag("enterPip", testApp, rotation) }
-            repeat { 1 }
-            setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                }
-                eachRun {
-                    device.pressHome()
-                    testApp.open()
-                    this.setRotation(rotation)
-                }
-            }
-            teardown {
-                eachRun {
-                    if (device.hasPipWindow()) {
-                        device.closePipWindow()
-                    }
-                    testApp.exit()
-                    this.setRotation(Surface.ROTATION_0)
-                }
-                test {
-                    if (device.hasPipWindow()) {
-                        device.closePipWindow()
-                    }
-                }
-            }
-            transitions {
-                testApp.clickEnterPipButton()
-                device.expandPipWindow()
-            }
-            assertions {
-                windowManagerTrace {
-                    navBarWindowIsAlwaysVisible()
-                    statusBarWindowIsAlwaysVisible()
-                    all("pipWindowBecomesVisible") {
-                        this.showsAppWindow(testApp.`package`)
-                                .then()
-                                .showsAppWindow(PIP_WINDOW_NAME)
-                    }
-                }
-
-                layersTrace {
-                    navBarLayerIsAlwaysVisible()
-                    statusBarLayerIsAlwaysVisible()
-                    noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
-                    navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
-                    statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
-
-                    all("pipLayerBecomesVisible") {
-                        this.showsLayer(testApp.launcherName)
-                                .then()
-                                .showsLayer(PIP_WINDOW_NAME)
-                    }
-                }
-            }
-        }
-    }
-
+    testName: String,
+    flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<Array<Any>> {
-            val supportedRotations = intArrayOf(Surface.ROTATION_0)
-            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+        fun getParams(): List<Array<Any>> {
+            val instrumentation = InstrumentationRegistry.getInstrumentation()
+            val testApp = PipAppHelper(instrumentation)
+            return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+                .buildTest { configuration ->
+                    withTestName { buildTestTag("enterPip", testApp, configuration) }
+                    repeat { configuration.repetitions }
+                    setup {
+                        test {
+                            device.wakeUpAndGoToHomeScreen()
+                        }
+                        eachRun {
+                            device.pressHome()
+                            testApp.open()
+                            this.setRotation(configuration.startRotation)
+                        }
+                    }
+                    teardown {
+                        eachRun {
+                            if (device.hasPipWindow()) {
+                                device.closePipWindow()
+                            }
+                            testApp.exit()
+                            this.setRotation(Surface.ROTATION_0)
+                        }
+                        test {
+                            if (device.hasPipWindow()) {
+                                device.closePipWindow()
+                            }
+                        }
+                    }
+                    transitions {
+                        testApp.clickEnterPipButton()
+                        device.expandPipWindow()
+                    }
+                    assertions {
+                        windowManagerTrace {
+                            navBarWindowIsAlwaysVisible()
+                            statusBarWindowIsAlwaysVisible()
+
+                            all("pipWindowBecomesVisible") {
+                                this.showsAppWindow(testApp.`package`)
+                                    .then()
+                                    .showsAppWindow(PIP_WINDOW_TITLE)
+                            }
+                        }
+
+                        layersTrace {
+                            navBarLayerIsAlwaysVisible(bugId = 140855415)
+                            statusBarLayerIsAlwaysVisible()
+                            noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0,
+                                enabled = false)
+                            navBarLayerRotatesAndScales(configuration.startRotation,
+                                Surface.ROTATION_0, bugId = 140855415)
+                            statusBarLayerRotatesScales(configuration.startRotation,
+                                Surface.ROTATION_0)
+                        }
+
+                        layersTrace {
+                            all("pipLayerBecomesVisible") {
+                                this.showsLayer(testApp.launcherName)
+                                    .then()
+                                    .showsLayer(PIP_WINDOW_TITLE)
+                            }
+                        }
+                    }
+                }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index abb8fc5..6b44ce6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -16,33 +16,28 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.content.ComponentName
-import android.graphics.Region
-import android.util.Log
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
-import android.view.WindowManager
 import androidx.test.filters.RequiresDevice
-import com.android.compatibility.common.util.SystemUtil
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.dsl.runWithFlicker
+import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.hasPipWindow
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
 import com.android.wm.shell.flicker.IME_WINDOW_NAME
-import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_WINDOW_NAME
 import com.android.wm.shell.flicker.helpers.ImeAppHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
-import java.io.IOException
 
 /**
  * Test Pip launch.
  * To run this test: `atest WMShellFlickerTests:PipKeyboardTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -50,9 +45,6 @@
     rotationName: String,
     rotation: Int
 ) : PipTestBase(rotationName, rotation) {
-    private val windowManager: WindowManager =
-            instrumentation.context.getSystemService(WindowManager::class.java)
-
     private val keyboardApp = ImeAppHelper(instrumentation)
 
     private val keyboardScenario: FlickerBuilder
@@ -71,7 +63,7 @@
                     // open an app with an input field and a keyboard
                     // UiAutomator doesn't support to launch the multiple Activities in a task.
                     // So use launchActivity() for the Keyboard Activity.
-                    launchActivity(TEST_APP_IME_ACTIVITY_COMPONENT_NAME)
+                    keyboardApp.launchViaIntent()
                 }
             }
             teardown {
@@ -103,10 +95,8 @@
             assertions {
                 windowManagerTrace {
                     all("PiP window must remain inside visible bounds") {
-                        coversAtMostRegion(
-                                partialWindowTitle = "PipActivity",
-                                region = Region(windowManager.maximumWindowMetrics.bounds)
-                        )
+                        val displayBounds = WindowUtils.getDisplayBounds(rotation)
+                        coversAtMostRegion(testApp.defaultWindowName, displayBounds)
                     }
                 }
             }
@@ -132,74 +122,13 @@
             assertions {
                 windowManagerTrace {
                     end {
-                        isAboveWindow(IME_WINDOW_NAME, TEST_APP_PIP_ACTIVITY_WINDOW_NAME)
+                        isAboveWindow(IME_WINDOW_NAME, testApp.defaultWindowName)
                     }
                 }
             }
         }
     }
 
-    private fun launchActivity(
-        activity: ComponentName? = null,
-        action: String? = null,
-        flags: Set<Int> = setOf(),
-        boolExtras: Map<String, Boolean> = mapOf(),
-        intExtras: Map<String, Int> = mapOf(),
-        stringExtras: Map<String, String> = mapOf()
-    ) {
-        require(activity != null || !action.isNullOrBlank()) {
-            "Cannot launch an activity with neither activity name nor action!"
-        }
-        val command = composeCommand(
-                "start", activity, action, flags, boolExtras, intExtras, stringExtras)
-        executeShellCommand(command)
-    }
-
-    private fun composeCommand(
-        command: String,
-        activity: ComponentName?,
-        action: String?,
-        flags: Set<Int>,
-        boolExtras: Map<String, Boolean>,
-        intExtras: Map<String, Int>,
-        stringExtras: Map<String, String>
-    ): String = buildString {
-        append("am ")
-        append(command)
-        activity?.let {
-            append(" -n ")
-            append(it.flattenToShortString())
-        }
-        action?.let {
-            append(" -a ")
-            append(it)
-        }
-        flags.forEach {
-            append(" -f ")
-            append(it)
-        }
-        boolExtras.forEach {
-            append(it.withFlag("ez"))
-        }
-        intExtras.forEach {
-            append(it.withFlag("ei"))
-        }
-        stringExtras.forEach {
-            append(it.withFlag("es"))
-        }
-    }
-
-    private fun Map.Entry<String, *>.withFlag(flag: String): String = " --$flag $key $value"
-
-    private fun executeShellCommand(cmd: String): String {
-        try {
-            return SystemUtil.runShellCommand(instrumentation, cmd)
-        } catch (e: IOException) {
-            Log.e("FlickerTests", "Error running shell command: $cmd")
-            throw e
-        }
-    }
-
     companion object {
         private const val TEST_REPETITIONS = 10
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
new file mode 100644
index 0000000..322034c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.content.Intent
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.dsl.runFlicker
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.wm.shell.flicker.helpers.PipAppHelper
+import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_PIP_ORIENTATION
+import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
+import org.junit.Assert.assertEquals
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip with orientation changes.
+ * To run this test: `atest WMShellFlickerTests:PipOrientationTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipOrientationTest(
+    rotationName: String,
+    rotation: Int
+) : AppTestBase(rotationName, rotation) {
+    // Helper class to process test actions by broadcast.
+    private inner class BroadcastActionTrigger {
+        private fun createIntentWithAction(broadcastAction: String): Intent {
+            return Intent(broadcastAction).setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+        }
+        fun doAction(broadcastAction: String) {
+            instrumentation.getContext().sendBroadcast(createIntentWithAction(broadcastAction))
+        }
+        fun requestOrientationForPip(orientation: Int) {
+            instrumentation.getContext()
+                    .sendBroadcast(createIntentWithAction(ACTION_SET_REQUESTED_ORIENTATION)
+                    .putExtra(EXTRA_PIP_ORIENTATION, orientation.toString()))
+        }
+    }
+    private val broadcastActionTrigger = BroadcastActionTrigger()
+
+    // Corresponds to ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+    private val ORIENTATION_LANDSCAPE = 0
+    // Corresponds to ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+    private val ORIENTATION_PORTRAIT = 1
+
+    private val testApp = FixedAppHelper(instrumentation)
+    private val pipApp = PipAppHelper(instrumentation)
+
+    @Test
+    fun testEnterPipToOtherOrientation() {
+        runFlicker(instrumentation) {
+            withTestName { "testEnterPipToOtherOrientation" }
+            setup {
+                test {
+                    removeAllTasksButHome()
+                    device.wakeUpAndGoToHomeScreen()
+                    // Launch a portrait only app on the fullscreen stack
+                    testApp.launchViaIntent(stringExtras = mapOf(
+                            EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString()))
+                    waitForAnimationComplete()
+                    // Launch the PiP activity fixed as landscape
+                    pipApp.launchViaIntent(stringExtras = mapOf(
+                            EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
+                    waitForAnimationComplete()
+                }
+            }
+            transitions {
+                // Enter PiP, and assert that the PiP is within bounds now that the device is back
+                // in portrait
+                broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
+                waitForAnimationComplete()
+            }
+            teardown {
+                test {
+                    removeAllTasksButHome()
+                }
+            }
+            assertions {
+                windowManagerTrace {
+                    all("pipApp window is always on top") {
+                        showsAppWindowOnTop(pipApp.defaultWindowName)
+                    }
+                    start("pipApp window hides testApp") {
+                        hidesAppWindow(testApp.defaultWindowName)
+                    }
+                    end("testApp windows is shown") {
+                        showsAppWindow(testApp.defaultWindowName)
+                    }
+                    navBarWindowIsAlwaysVisible()
+                    statusBarWindowIsAlwaysVisible()
+                }
+                layersTrace {
+                    val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
+                    val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
+                    start("pipApp layer hides testApp") {
+                        hasVisibleRegion(pipApp.defaultWindowName, startingBounds)
+                        hidesLayer(testApp.defaultWindowName)
+                    }
+                    end("testApp layer covers fullscreen") {
+                        hasVisibleRegion(testApp.defaultWindowName, endingBounds)
+                    }
+                    navBarLayerIsAlwaysVisible(bugId = 140855415)
+                    statusBarLayerIsAlwaysVisible(bugId = 140855415)
+                }
+            }
+        }
+    }
+
+    @Test
+    fun testSetRequestedOrientationWhilePinned() {
+        runFlicker(instrumentation) {
+            withTestName { "testSetRequestedOrientationWhilePinned" }
+            setup {
+                test {
+                    removeAllTasksButHome()
+                    device.wakeUpAndGoToHomeScreen()
+                    // Launch the PiP activity fixed as landscape
+                    pipApp.launchViaIntent(stringExtras = mapOf(
+                            EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(),
+                            EXTRA_ENTER_PIP to "true"))
+                    waitForAnimationComplete()
+                    assertEquals(Surface.ROTATION_0, device.displayRotation)
+                }
+            }
+            transitions {
+                // Request that the orientation is set to landscape
+                broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE)
+
+                // Launch the activity back into fullscreen and ensure that it is now in landscape
+                pipApp.launchViaIntent()
+                waitForAnimationComplete()
+                assertEquals(Surface.ROTATION_90, device.displayRotation)
+            }
+            teardown {
+                test {
+                    removeAllTasksButHome()
+                }
+            }
+            assertions {
+                val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
+                val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
+                windowManagerTrace {
+                    start("PIP window must remain inside display") {
+                        coversAtMostRegion(pipApp.defaultWindowName, startingBounds)
+                    }
+                    end("pipApp shows on top") {
+                        showsAppWindowOnTop(pipApp.defaultWindowName)
+                    }
+                    navBarWindowIsAlwaysVisible()
+                    statusBarWindowIsAlwaysVisible()
+                }
+                layersTrace {
+                    start("PIP layer must remain inside display") {
+                        coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
+                    }
+                    end("pipApp layer covers fullscreen") {
+                        hasVisibleRegion(pipApp.defaultWindowName, endingBounds)
+                    }
+                    navBarLayerIsAlwaysVisible(bugId = 140855415)
+                    statusBarLayerIsAlwaysVisible(bugId = 140855415)
+                }
+            }
+        }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> {
+            val supportedRotations = intArrayOf(Surface.ROTATION_0)
+            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
new file mode 100644
index 0000000..96d98d5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.wm.shell.flicker.helpers.PipAppHelper
+import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
+import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.noUncoveredRegions
+import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarLayerRotatesScales
+import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip Stack in bounds after rotations.
+ * To run this test: `atest WMShellFlickerTests:PipRotationTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipRotationTest(
+    testName: String,
+    flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> {
+            val instrumentation = InstrumentationRegistry.getInstrumentation()
+            val testApp = FixedAppHelper(instrumentation)
+            val pipApp = PipAppHelper(instrumentation)
+            return FlickerTestRunnerFactory(instrumentation,
+                    listOf(Surface.ROTATION_0, Surface.ROTATION_90))
+                    .buildRotationTest { configuration ->
+                        withTestName { buildTestTag("PipRotationTest", testApp, configuration) }
+                        repeat { configuration.repetitions }
+                        setup {
+                            test {
+                                AppTestBase.removeAllTasksButHome()
+                                device.wakeUpAndGoToHomeScreen()
+                                pipApp.launchViaIntent(stringExtras = mapOf(
+                                        EXTRA_ENTER_PIP to "true"))
+                                testApp.launchViaIntent()
+                                AppTestBase.waitForAnimationComplete()
+                            }
+                            eachRun {
+                                setRotation(configuration.startRotation)
+                            }
+                        }
+                        transitions {
+                            setRotation(configuration.endRotation)
+                        }
+                        teardown {
+                            eachRun {
+                                setRotation(Surface.ROTATION_0)
+                            }
+                            test {
+                                AppTestBase.removeAllTasksButHome()
+                            }
+                        }
+                        assertions {
+                            windowManagerTrace {
+                                navBarWindowIsAlwaysVisible()
+                                statusBarWindowIsAlwaysVisible()
+                            }
+                            layersTrace {
+                                navBarLayerIsAlwaysVisible(bugId = 140855415)
+                                statusBarLayerIsAlwaysVisible(bugId = 140855415)
+                                noUncoveredRegions(configuration.startRotation,
+                                        configuration.endRotation, allStates = false)
+                                navBarLayerRotatesAndScales(configuration.startRotation,
+                                        configuration.endRotation)
+                                statusBarLayerRotatesScales(configuration.startRotation,
+                                        configuration.endRotation)
+                            }
+                            layersTrace {
+                                val startingBounds = WindowUtils.getDisplayBounds(
+                                        configuration.startRotation)
+                                val endingBounds = WindowUtils.getDisplayBounds(
+                                        configuration.endRotation)
+                                start("appLayerRotates_StartingBounds") {
+                                    hasVisibleRegion(testApp.defaultWindowName, startingBounds)
+                                    coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
+                                }
+                                end("appLayerRotates_EndingBounds") {
+                                    hasVisibleRegion(testApp.defaultWindowName, endingBounds)
+                                    coversAtMostRegion(endingBounds, pipApp.defaultWindowName)
+                                }
+                            }
+                        }
+                    }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
new file mode 100644
index 0000000..d20552f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.dsl.runFlicker
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.helpers.ImeAppHelper
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.wm.shell.flicker.helpers.PipAppHelper
+import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip with split-screen.
+ * To run this test: `atest WMShellFlickerTests:PipSplitScreenTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 161435597)
+class PipSplitScreenTest(
+    rotationName: String,
+    rotation: Int
+) : AppTestBase(rotationName, rotation) {
+    private val pipApp = PipAppHelper(instrumentation)
+    private val imeApp = ImeAppHelper(instrumentation)
+    private val testApp = FixedAppHelper(instrumentation)
+
+    @Test
+    fun testShowsPipLaunchingToSplitScreen() {
+        runFlicker(instrumentation) {
+            withTestName { "testShowsPipLaunchingToSplitScreen" }
+            repeat { TEST_REPETITIONS }
+            setup {
+                test {
+                    removeAllTasksButHome()
+                    device.wakeUpAndGoToHomeScreen()
+                    pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"))
+                    waitForAnimationComplete()
+                }
+            }
+            transitions {
+                testApp.launchViaIntent()
+                device.launchSplitScreen()
+                imeApp.launchViaIntent()
+                waitForAnimationComplete()
+            }
+            teardown {
+                eachRun {
+                    imeApp.exit()
+                    if (device.isInSplitScreen()) {
+                        device.exitSplitScreen()
+                    }
+                    testApp.exit()
+                }
+                test {
+                    removeAllTasksButHome()
+                }
+            }
+            assertions {
+                val displayBounds = WindowUtils.getDisplayBounds(rotation)
+                windowManagerTrace {
+                    all("PIP window must remain inside visible bounds") {
+                        coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+                    }
+                    end("Both app windows should be visible") {
+                        showsAppWindow(testApp.defaultWindowName)
+                        showsAppWindow(imeApp.defaultWindowName)
+                        noWindowsOverlap(testApp.defaultWindowName, imeApp.defaultWindowName)
+                    }
+                    navBarWindowIsAlwaysVisible()
+                    statusBarWindowIsAlwaysVisible()
+                }
+                layersTrace {
+                    all("PIP layer must remain inside visible bounds") {
+                        coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
+                    }
+                    end("Both app layers should be visible") {
+                        coversAtMostRegion(displayBounds, testApp.defaultWindowName)
+                        coversAtMostRegion(displayBounds, imeApp.defaultWindowName)
+                    }
+                    navBarLayerIsAlwaysVisible()
+                    statusBarLayerIsAlwaysVisible()
+                }
+            }
+        }
+    }
+
+    companion object {
+        const val TEST_REPETITIONS = 2
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> {
+            val supportedRotations = intArrayOf(Surface.ROTATION_0)
+            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
index c1c34ec..03a9211 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
@@ -16,12 +16,11 @@
 
 package com.android.wm.shell.flicker.pip
 
-import com.android.wm.shell.flicker.NonRotationTestBase
 import com.android.wm.shell.flicker.helpers.PipAppHelper
 
 abstract class PipTestBase(
     rotationName: String,
     rotation: Int
-) : NonRotationTestBase(rotationName, rotation) {
+) : AppTestBase(rotationName, rotation) {
     protected val testApp = PipAppHelper(instrumentation)
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
similarity index 95%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index ac54a0a..e1fa657 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+package com.android.wm.shell.flicker.pip
 
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -24,7 +24,6 @@
 import com.android.server.wm.flicker.FlickerTestRunner
 import com.android.server.wm.flicker.FlickerTestRunnerFactory
 import com.android.server.wm.flicker.focusChanges
-import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.expandPipWindow
@@ -40,6 +39,7 @@
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.helpers.PipAppHelper
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -47,7 +47,7 @@
 
 /**
  * Test Pip launch.
- * To run this test: `atest FlickerTests:PipToAppTest`
+ * To run this test: `atest WMShellFlickerTests:PipToAppTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
@@ -75,7 +75,7 @@
                         }
                         eachRun {
                             this.setRotation(configuration.startRotation)
-                            testApp.clickEnterPipButton(device)
+                            testApp.clickEnterPipButton()
                             device.hasPipWindow()
                         }
                     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
similarity index 94%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
index f14a27d..bf11937 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+package com.android.wm.shell.flicker.pip
 
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -24,7 +24,6 @@
 import com.android.server.wm.flicker.FlickerTestRunner
 import com.android.server.wm.flicker.FlickerTestRunnerFactory
 import com.android.server.wm.flicker.focusChanges
-import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.hasPipWindow
@@ -39,6 +38,7 @@
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.helpers.PipAppHelper
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -46,7 +46,7 @@
 
 /**
  * Test Pip launch.
- * To run this test: `atest FlickerTests:PipToHomeTest`
+ * To run this test: `atest WMShellFlickerTests:PipToHomeTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
@@ -74,7 +74,7 @@
                         eachRun {
                             testApp.open()
                             this.setRotation(configuration.startRotation)
-                            testApp.clickEnterPipButton(device)
+                            testApp.clickEnterPipButton()
                             device.hasPipWindow()
                         }
                     }
@@ -93,7 +93,7 @@
                         }
                     }
                     transitions {
-                        testApp.closePipWindow(device)
+                        testApp.closePipWindow()
                     }
                     assertions {
                         windowManagerTrace {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index 871732c..4cb6447 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -20,7 +20,12 @@
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.UiObject2
 import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_CLEAR
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_NO_OP
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_OFF
+import com.android.wm.shell.flicker.TEST_APP_PIP_MENU_ACTION_ON
 import com.android.wm.shell.flicker.wait
+import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
@@ -128,6 +133,7 @@
         testApp.clickStartMediaSessionButton()
 
         enterPip_openMenu_assertShown()
+        assertFullscreenAndCloseButtonsAreShown()
 
         // PiP menu should contain the Pause button
         val pauseButton = uiDevice.findTvPipMenuElementWithDescription(pauseButtonDescription)
@@ -137,6 +143,7 @@
         // When we pause media, the button should change from Pause to Play
         pauseButton.click()
 
+        assertFullscreenAndCloseButtonsAreShown()
         // PiP menu should contain the Play button now
         uiDevice.waitForTvPipMenuElementWithDescription(playButtonDescription)
                 ?: fail("\"Play\" button should be shown in Pip menu if there is an active " +
@@ -145,10 +152,99 @@
         testApp.closePipWindow()
     }
 
+    @Test
+    fun pipMenu_withCustomActions() {
+        // Enter PiP with custom actions.
+        testApp.checkWithCustomActionsCheckbox()
+        enterPip_openMenu_assertShown()
+
+        // PiP menu should contain "No-Op", "Off" and "Clear" buttons...
+        uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP)
+                ?: fail("\"No-Op\" button should be shown in Pip menu")
+        val offButton = uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_OFF)
+                ?: fail("\"Off\" button should be shown in Pip menu")
+        uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR)
+                ?: fail("\"Clear\" button should be shown in Pip menu")
+        // ... and should also contain the "Full screen" and "Close" buttons.
+        assertFullscreenAndCloseButtonsAreShown()
+
+        offButton.click()
+        // Invoking the "Off" action should replace it with the "On" action/button and should
+        // remove the "No-Op" action/button. "Clear" action/button should remain in the menu ...
+        uiDevice.waitForTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_ON)
+                ?: fail("\"On\" button should be shown in Pip for a corresponding custom action")
+        assertNull("\"No-Op\" button should not be shown in Pip menu",
+                uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP))
+        val clearButton =
+                uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR)
+                        ?: fail("\"Clear\" button should be shown in Pip menu")
+        // ... as well as the "Full screen" and "Close" buttons.
+        assertFullscreenAndCloseButtonsAreShown()
+
+        clearButton.click()
+        // Invoking the "Clear" action should remove all the custom actions and their corresponding
+        // buttons, ...
+        uiDevice.waitUntilTvPipMenuElementWithDescriptionIsGone(TEST_APP_PIP_MENU_ACTION_ON)?.also {
+            isGone -> if (!isGone) fail("\"On\" button should not be shown in Pip menu")
+        }
+        assertNull("\"Off\" button should not be shown in Pip menu",
+                uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_OFF))
+        assertNull("\"Clear\" button should not be shown in Pip menu",
+                uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR))
+        assertNull("\"No-Op\" button should not be shown in Pip menu",
+                uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP))
+        // ... but the menu should still contain the "Full screen" and "Close" buttons.
+        assertFullscreenAndCloseButtonsAreShown()
+
+        testApp.closePipWindow()
+    }
+
+    @Test
+    fun pipMenu_customActions_override_mediaControls() {
+        // Start media session before entering PiP with custom actions.
+        testApp.clickStartMediaSessionButton()
+        testApp.checkWithCustomActionsCheckbox()
+        enterPip_openMenu_assertShown()
+
+        // PiP menu should contain "No-Op", "Off" and "Clear" buttons for the custom actions...
+        uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_NO_OP)
+                ?: fail("\"No-Op\" button should be shown in Pip menu")
+        uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_OFF)
+                ?: fail("\"Off\" button should be shown in Pip menu")
+        val clearButton =
+                uiDevice.findTvPipMenuElementWithDescription(TEST_APP_PIP_MENU_ACTION_CLEAR)
+                        ?: fail("\"Clear\" button should be shown in Pip menu")
+        // ... should also contain the "Full screen" and "Close" buttons, ...
+        assertFullscreenAndCloseButtonsAreShown()
+        // ... but should not contain media buttons.
+        assertNull("\"Play\" button should not be shown in menu when there are custom actions",
+                uiDevice.findTvPipMenuElementWithDescription(playButtonDescription))
+        assertNull("\"Pause\" button should not be shown in menu when there are custom actions",
+                uiDevice.findTvPipMenuElementWithDescription(pauseButtonDescription))
+
+        clearButton.click()
+        // Invoking the "Clear" action should remove all the custom actions, which should bring up
+        // media buttons...
+        uiDevice.waitForTvPipMenuElementWithDescription(pauseButtonDescription)
+                ?: fail("\"Pause\" button should be shown in Pip menu if there is an active " +
+                        "playing media session.")
+        // ... while the "Full screen" and "Close" buttons should remain in the menu.
+        assertFullscreenAndCloseButtonsAreShown()
+
+        testApp.closePipWindow()
+    }
+
     private fun enterPip_openMenu_assertShown(): UiObject2 {
         testApp.clickEnterPipButton()
         // Pressing the Window key should bring up Pip menu
         uiDevice.pressWindowKey()
         return uiDevice.waitForTvPipMenu() ?: fail("Pip menu should have been shown")
     }
+
+    private fun assertFullscreenAndCloseButtonsAreShown() {
+        uiDevice.findTvPipMenuCloseButton()
+                ?: fail("\"Close PIP\" button should be shown in Pip menu")
+        uiDevice.findTvPipMenuFullscreenButton()
+                ?: fail("\"Full screen\" button should be shown in Pip menu")
+    }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
index 8db8bc67..0732794 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -58,6 +58,9 @@
             ?.findObject(buttonSelector)
 }
 
+fun UiDevice.waitUntilTvPipMenuElementWithDescriptionIsGone(desc: String): Boolean? =
+    wait(Until.gone(By.copy(tvPipMenuSelector).hasDescendant(By.desc(desc))), WAIT_TIME_MS)
+
 fun UiObject2.isFullscreen(uiDevice: UiDevice): Boolean = visibleBounds.run {
     height() == uiDevice.displayHeight && width() == uiDevice.displayWidth
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
index a0056df..c61a0f1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -38,6 +39,7 @@
  * Test SplitScreen launch.
  * To run this test: `atest WMShellFlickerTests:EnterSplitScreenTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
index 32e112d..bf92869 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.util.Rational
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -40,6 +41,7 @@
  * Test exit SplitScreen mode.
  * To run this test: `atest WMShellFlickerTests:ExitSplitScreenTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
similarity index 96%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index ae9fcf9..1e328a8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.splitscreen
+package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
@@ -48,7 +48,7 @@
 
 /**
  * Test open app to split screen.
- * To run this test: `atest FlickerTests:OpenAppToSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:OpenAppToSplitScreenTest`
  */
 @Presubmit
 @RequiresDevice
@@ -65,7 +65,7 @@
         fun getParams(): Collection<Array<Any>> {
             val instrumentation = InstrumentationRegistry.getInstrumentation()
             val testApp = StandardAppHelper(instrumentation,
-                "com.android.server.wm.flicker.testapp", "SimpleApp")
+                "com.android.wm.shell.flicker.testapp", "SimpleApp")
 
             return FlickerTestRunnerFactory(instrumentation)
                 .buildTest { configuration ->
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ResizeSplitScreenTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ResizeSplitScreenTest.kt
index 4b9f024..7c83846 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.splitscreen
+package com.android.wm.shell.flicker.splitscreen
 
 import android.graphics.Region
 import android.util.Rational
@@ -29,8 +29,8 @@
 import com.android.server.wm.flicker.FlickerTestRunnerFactory
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.exitSplitScreen
@@ -55,7 +55,7 @@
 
 /**
  * Test split screen resizing window transitions.
- * To run this test: `atest FlickerTests:ResizeSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:ResizeSplitScreenTest`
  *
  * Currently it runs only in 0 degrees because of b/156100803
  */
@@ -78,7 +78,7 @@
         fun getParams(): Collection<Array<Any>> {
             val instrumentation = InstrumentationRegistry.getInstrumentation()
             val testAppTop = StandardAppHelper(instrumentation,
-                "com.android.server.wm.flicker.testapp", "SimpleApp")
+                "com.android.wm.shell.flicker.testapp", "SimpleApp")
             val testAppBottom = ImeAppHelper(instrumentation)
 
             return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt
index 496fe94..a3440df 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt
@@ -17,11 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import com.android.wm.shell.flicker.NonRotationTestBase
-import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME
 import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL
-import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME
 import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_LABEL
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import com.android.wm.shell.flicker.testapp.Components
 
 abstract class SplitScreenTestBase(
     rotationName: String,
@@ -29,8 +28,8 @@
 ) : NonRotationTestBase(rotationName, rotation) {
     protected val splitScreenApp = SplitScreenHelper(instrumentation,
             TEST_APP_SPLITSCREEN_PRIMARY_LABEL,
-            TEST_APP_SPLITSCREEN_PRIMARY_COMPONENT_NAME)
+            Components.SplitScreenActivity())
     protected val secondaryApp = SplitScreenHelper(instrumentation,
             TEST_APP_SPLITSCREEN_SECONDARY_LABEL,
-            TEST_APP_SPLITSCREEN_SECONDARY_COMPONENT_NAME)
+            Components.SplitScreenSecondaryActivity())
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenToLauncherTest.kt
similarity index 96%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenToLauncherTest.kt
index f966a66..00979fa 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.splitscreen
+package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
@@ -48,7 +48,7 @@
 
 /**
  * Test open app to split screen.
- * To run this test: `atest FlickerTests:SplitScreenToLauncherTest`
+ * To run this test: `atest WMShellFlickerTests:SplitScreenToLauncherTest`
  */
 @Presubmit
 @RequiresDevice
@@ -64,7 +64,7 @@
         fun getParams(): Collection<Array<Any>> {
             val instrumentation = InstrumentationRegistry.getInstrumentation()
             val testApp = StandardAppHelper(instrumentation,
-                "com.android.server.wm.flicker.testapp", "SimpleApp")
+                "com.android.wm.shell.flicker.testapp", "SimpleApp")
 
             // b/161435597 causes the test not to work on 90 degrees
             return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
index d12b492..26627a4 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
@@ -18,3 +18,9 @@
     sdk_version: "current",
     test_suites: ["device-tests"],
 }
+
+java_library {
+    name: "wmshell-flicker-test-components",
+    srcs: ["src/**/Components.java"],
+    sdk_version: "test_current",
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
index 2ce1204..a583b72 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -21,13 +21,25 @@
          android:targetSdkVersion="29"/>
     <application android:allowBackup="false"
          android:supportsRtl="true">
+        <activity android:name=".FixedActivity"
+                  android:resizeableActivity="true"
+                  android:supportsPictureInPicture="true"
+                  android:launchMode="singleTop"
+                  android:label="FixedApp"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
         <activity android:name=".PipActivity"
-             android:resizeableActivity="true"
-             android:supportsPictureInPicture="true"
-             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
-             android:taskAffinity="com.android.wm.shell.flicker.testapp.PipActivity"
-             android:label="PipApp"
-             android:exported="true">
+                 android:resizeableActivity="true"
+                 android:supportsPictureInPicture="true"
+                 android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+                 android:taskAffinity="com.android.wm.shell.flicker.testapp.PipActivity"
+                 android:launchMode="singleTop"
+                 android:label="PipApp"
+                 android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
@@ -39,9 +51,9 @@
         </activity>
 
         <activity android:name=".ImeActivity"
-             android:taskAffinity="com.android.wm.shell.flicker.testapp.ImeActivity"
-             android:label="ImeApp"
-             android:exported="true">
+                 android:taskAffinity="com.android.wm.shell.flicker.testapp.ImeActivity"
+                 android:label="ImeApp"
+                 android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
@@ -73,5 +85,15 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+
+        <activity android:name=".SimpleActivity"
+                  android:taskAffinity="com.android.wm.shell.flicker.testapp.SimpleActivity"
+                  android:label="SimpleApp"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
index b4a4c16..e5d2f82 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -28,6 +28,12 @@
         android:text="Enter PIP"
         android:onClick="enterPip"/>
 
+    <CheckBox
+        android:id="@+id/with_custom_actions"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="With custom actions"/>
+
     <RadioGroup
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_simple.xml
similarity index 76%
rename from tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
rename to libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_simple.xml
index 2c58d91..5d94e51 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_simple.xml
@@ -18,9 +18,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@android:color/holo_blue_bright">
-    <Button android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/enter_pip"
-            android:text="Enter PIP"/>
+    android:background="@android:color/holo_orange_light">
+
 </LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java
new file mode 100644
index 0000000..8e9b4cb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.testapp;
+
+import android.content.ComponentName;
+
+public class Components {
+    public abstract static class ComponentsInfo {
+        public ComponentName getComponentName() {
+            return ComponentName.createRelative(PACKAGE_NAME, "." + getActivityName());
+        }
+        public abstract String getActivityName();
+    }
+
+    public static final String PACKAGE_NAME = "com.android.wm.shell.flicker.testapp";
+
+    public static class FixedActivity extends ComponentsInfo {
+        // Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
+        public static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
+
+        @Override
+        public String getActivityName() {
+            return FixedActivity.class.getSimpleName();
+        }
+    }
+
+    public static class PipActivity extends ComponentsInfo {
+        // Intent action that this activity dynamically registers to enter picture-in-picture
+        public static final String ACTION_ENTER_PIP = PACKAGE_NAME + ".PipActivity.ENTER_PIP";
+        // Intent action that this activity dynamically registers to set requested orientation.
+        // Will apply the oriention to the value set in the EXTRA_FIXED_ORIENTATION extra.
+        public static final String ACTION_SET_REQUESTED_ORIENTATION =
+                PACKAGE_NAME + ".PipActivity.SET_REQUESTED_ORIENTATION";
+
+        // Calls enterPictureInPicture() on creation
+        public static final String EXTRA_ENTER_PIP = "enter_pip";
+        // Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
+        public static final String EXTRA_PIP_ORIENTATION = "fixed_orientation";
+        // Adds a click listener to finish this activity when it is clicked
+        public static final String EXTRA_TAP_TO_FINISH = "tap_to_finish";
+
+        @Override
+        public String getActivityName() {
+            return PipActivity.class.getSimpleName();
+        }
+    }
+
+    public static class ImeActivity extends ComponentsInfo {
+        @Override
+        public String getActivityName() {
+            return ImeActivity.class.getSimpleName();
+        }
+    }
+
+    public static class SplitScreenActivity extends ComponentsInfo {
+        @Override
+        public String getActivityName() {
+            return SplitScreenActivity.class.getSimpleName();
+        }
+    }
+
+    public static class SplitScreenSecondaryActivity extends ComponentsInfo {
+        @Override
+        public String getActivityName() {
+            return SplitScreenSecondaryActivity.class.getSimpleName();
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/FixedActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/FixedActivity.java
new file mode 100644
index 0000000..d4ae6c1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/FixedActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.testapp;
+
+import static com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION;
+
+import android.os.Bundle;
+
+public class FixedActivity extends SimpleActivity {
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Set the fixed orientation if requested
+        if (getIntent().hasExtra(EXTRA_FIXED_ORIENTATION)) {
+            final int ori = Integer.parseInt(getIntent().getStringExtra(EXTRA_FIXED_ORIENTATION));
+            setRequestedOrientation(ori);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
index d2fcd0d..a6ba782 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -24,18 +24,38 @@
 import static android.media.session.PlaybackState.STATE_PLAYING;
 import static android.media.session.PlaybackState.STATE_STOPPED;
 
+import static com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP;
+import static com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION;
+import static com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP;
+import static com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_PIP_ORIENTATION;
+
 import android.app.Activity;
+import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
+import android.app.RemoteAction;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
 import android.media.MediaMetadata;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
+import android.util.Log;
 import android.util.Rational;
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
+import android.widget.CheckBox;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 public class PipActivity extends Activity {
+    private static final String TAG = PipActivity.class.getSimpleName();
     /**
      * A media session title for when the session is in {@link STATE_PLAYING}.
      * TvPipNotificationTests check whether the actual notification title matches this string.
@@ -52,7 +72,19 @@
     private static final Rational RATIO_WIDE = new Rational(2, 1);
     private static final Rational RATIO_TALL = new Rational(1, 2);
 
-    private PictureInPictureParams.Builder mPipParamsBuilder;
+    private static final String PIP_ACTION_NO_OP = "No-Op";
+    private static final String PIP_ACTION_OFF = "Off";
+    private static final String PIP_ACTION_ON = "On";
+    private static final String PIP_ACTION_CLEAR = "Clear";
+    private static final String ACTION_NO_OP = "com.android.wm.shell.flicker.testapp.NO_OP";
+    private static final String ACTION_SWITCH_OFF =
+            "com.android.wm.shell.flicker.testapp.SWITCH_OFF";
+    private static final String ACTION_SWITCH_ON = "com.android.wm.shell.flicker.testapp.SWITCH_ON";
+    private static final String ACTION_CLEAR = "com.android.wm.shell.flicker.testapp.CLEAR";
+
+    private final PictureInPictureParams.Builder mPipParamsBuilder =
+            new PictureInPictureParams.Builder()
+                    .setAspectRatio(RATIO_DEFAULT);
     private MediaSession mMediaSession;
     private final PlaybackState.Builder mPlaybackStateBuilder = new PlaybackState.Builder()
             .setActions(ACTION_PLAY | ACTION_PAUSE | ACTION_STOP)
@@ -60,6 +92,46 @@
     private PlaybackState mPlaybackState = mPlaybackStateBuilder.build();
     private final MediaMetadata.Builder mMediaMetadataBuilder = new MediaMetadata.Builder();
 
+    private final List<RemoteAction> mSwitchOffActions = new ArrayList<>();
+    private final List<RemoteAction> mSwitchOnActions = new ArrayList<>();
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (isInPictureInPictureMode()) {
+                switch (intent.getAction()) {
+                    case ACTION_SWITCH_ON:
+                        mPipParamsBuilder.setActions(mSwitchOnActions);
+                        break;
+                    case ACTION_SWITCH_OFF:
+                        mPipParamsBuilder.setActions(mSwitchOffActions);
+                        break;
+                    case ACTION_CLEAR:
+                        mPipParamsBuilder.setActions(Collections.emptyList());
+                        break;
+                    case ACTION_NO_OP:
+                        return;
+                    default:
+                        Log.w(TAG, "Unhandled action=" + intent.getAction());
+                        return;
+                }
+                setPictureInPictureParams(mPipParamsBuilder.build());
+            } else {
+                switch (intent.getAction()) {
+                    case ACTION_ENTER_PIP:
+                        enterPip(null);
+                        break;
+                    case ACTION_SET_REQUESTED_ORIENTATION:
+                        setRequestedOrientation(Integer.parseInt(intent.getStringExtra(
+                                EXTRA_PIP_ORIENTATION)));
+                        break;
+                    default:
+                        Log.w(TAG, "Unhandled action=" + intent.getAction());
+                        return;
+                }
+            }
+        }
+    };
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -72,9 +144,6 @@
 
         setContentView(R.layout.activity_pip);
 
-        mPipParamsBuilder = new PictureInPictureParams.Builder()
-                .setAspectRatio(RATIO_DEFAULT);
-
         findViewById(R.id.media_session_start)
                 .setOnClickListener(v -> updateMediaSessionState(STATE_PLAYING));
         findViewById(R.id.media_session_stop)
@@ -98,9 +167,52 @@
                 updateMediaSessionState(STATE_STOPPED);
             }
         });
+
+        // Build two sets of the custom actions. We'll replace one with the other when 'On'/'Off'
+        // action is invoked.
+        // The first set consists of 3 actions: 1) Off; 2) No-Op; 3) Clear.
+        // The second set consists of 2 actions: 1) On; 2) Clear.
+        // Upon invocation 'Clear' action clear-off all the custom actions, including itself.
+        final Icon icon = Icon.createWithResource(this, android.R.drawable.ic_menu_help);
+        final RemoteAction noOpAction = buildRemoteAction(icon, PIP_ACTION_NO_OP, ACTION_NO_OP);
+        final RemoteAction switchOnAction =
+                buildRemoteAction(icon, PIP_ACTION_ON, ACTION_SWITCH_ON);
+        final RemoteAction switchOffAction =
+                buildRemoteAction(icon, PIP_ACTION_OFF, ACTION_SWITCH_OFF);
+        final RemoteAction clearAllAction = buildRemoteAction(icon, PIP_ACTION_CLEAR, ACTION_CLEAR);
+        mSwitchOffActions.addAll(Arrays.asList(switchOnAction, clearAllAction));
+        mSwitchOnActions.addAll(Arrays.asList(noOpAction, switchOffAction, clearAllAction));
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_NO_OP);
+        filter.addAction(ACTION_SWITCH_ON);
+        filter.addAction(ACTION_SWITCH_OFF);
+        filter.addAction(ACTION_CLEAR);
+        filter.addAction(ACTION_SET_REQUESTED_ORIENTATION);
+        filter.addAction(ACTION_ENTER_PIP);
+        registerReceiver(mBroadcastReceiver, filter);
+
+        handleIntentExtra(getIntent());
+    }
+
+    @Override
+    protected void onDestroy() {
+        unregisterReceiver(mBroadcastReceiver);
+        super.onDestroy();
+    }
+
+    private RemoteAction buildRemoteAction(Icon icon, String label, String action) {
+        final Intent intent = new Intent(action);
+        final PendingIntent pendingIntent =
+                PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+        return new RemoteAction(icon, label, label, pendingIntent);
     }
 
     public void enterPip(View v) {
+        final boolean withCustomActions =
+                ((CheckBox) findViewById(R.id.with_custom_actions)).isChecked();
+        mPipParamsBuilder.setActions(
+                withCustomActions ? mSwitchOnActions : Collections.emptyList());
         enterPictureInPictureMode(mPipParamsBuilder.build());
     }
 
@@ -153,4 +265,17 @@
         mMediaSession.setMetadata(mMediaMetadataBuilder.build());
         mMediaSession.setActive(newState != STATE_STOPPED);
     }
+
+    private void handleIntentExtra(Intent intent) {
+        // Set the fixed orientation if requested
+        if (intent.hasExtra(EXTRA_PIP_ORIENTATION)) {
+            final int ori = Integer.parseInt(getIntent().getStringExtra(EXTRA_PIP_ORIENTATION));
+            setRequestedOrientation(ori);
+        }
+        // Enter picture in picture with the given aspect ratio if provided
+        if (intent.hasExtra(EXTRA_ENTER_PIP)) {
+            mPipParamsBuilder.setActions(mSwitchOnActions);
+            enterPip(null);
+        }
+    }
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/SimpleActivity.java
similarity index 62%
rename from tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
rename to libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/SimpleActivity.java
index 9a8f399..5343c18 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/SimpleActivity.java
@@ -14,17 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.testapp;
+package com.android.wm.shell.flicker.testapp;
 
 import android.app.Activity;
-import android.app.PictureInPictureParams;
-import android.graphics.Rect;
 import android.os.Bundle;
-import android.util.Rational;
 import android.view.WindowManager;
-import android.widget.Button;
 
-public class PipActivity extends Activity {
+public class SimpleActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -32,14 +28,6 @@
         p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
                 .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
         getWindow().setAttributes(p);
-        setContentView(R.layout.activity_pip);
-        Button enterPip = (Button) findViewById(R.id.enter_pip);
-
-        PictureInPictureParams params = new PictureInPictureParams.Builder()
-                .setAspectRatio(new Rational(1, 1))
-                .setSourceRectHint(new Rect(0, 0, 100, 100))
-                .build();
-
-        enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
+        setContentView(R.layout.activity_simple);
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
new file mode 100644
index 0000000..c9d32c4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.apppairs;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.SurfaceControl;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link AppPairLayout} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppPairLayoutTests extends ShellTestCase {
+    @Mock SurfaceControl mSurfaceControl;
+    private Display mDisplay;
+    private Configuration mConfiguration;
+    private AppPairLayout mAppPairLayout;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mConfiguration = getConfiguration(false);
+        mDisplay = mContext.getDisplay();
+        mAppPairLayout = new AppPairLayout(mContext, mDisplay, mConfiguration, mSurfaceControl);
+    }
+
+    @After
+    @UiThreadTest
+    public void tearDown() {
+        mAppPairLayout.release();
+    }
+
+    @Test
+    @UiThreadTest
+    public void testUpdateConfiguration() {
+        assertThat(mAppPairLayout.updateConfiguration(getConfiguration(false))).isFalse();
+        assertThat(mAppPairLayout.updateConfiguration(getConfiguration(true))).isTrue();
+    }
+
+    @Test
+    @UiThreadTest
+    public void testInitRelease() {
+        mAppPairLayout.init();
+        assertThat(mAppPairLayout.getDividerLeash()).isNotNull();
+        mAppPairLayout.release();
+        assertThat(mAppPairLayout.getDividerLeash()).isNull();
+    }
+
+    private static Configuration getConfiguration(boolean isLandscape) {
+        final Configuration configuration = new Configuration();
+        configuration.unset();
+        configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+        configuration.windowConfiguration.setBounds(
+                new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160));
+        return configuration;
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
index 754f732..f12648a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
@@ -34,7 +34,6 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import org.junit.After;
 import org.junit.Before;
@@ -52,7 +51,6 @@
     @Mock private SyncTransactionQueue mSyncQueue;
     @Mock private ShellTaskOrganizer mTaskOrganizer;
     @Mock private DisplayController mDisplayController;
-    @Mock private TaskStackListenerImpl mTaskStackListener;
 
     @Before
     public void setUp() {
@@ -60,8 +58,7 @@
         mController = new TestAppPairsController(
                 mTaskOrganizer,
                 mSyncQueue,
-                mDisplayController,
-                mTaskStackListener);
+                mDisplayController);
         when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
         when(mDisplayController.getDisplay(anyInt())).thenReturn(
                 mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
index 6d441ab..f8c68d2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
@@ -34,7 +34,6 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import org.junit.After;
 import org.junit.Before;
@@ -52,7 +51,6 @@
     @Mock private SyncTransactionQueue mSyncQueue;
     @Mock private ShellTaskOrganizer mTaskOrganizer;
     @Mock private DisplayController mDisplayController;
-    @Mock private TaskStackListenerImpl mTaskStackListener;
 
     @Before
     public void setUp() {
@@ -60,8 +58,7 @@
         mController = new TestAppPairsController(
                 mTaskOrganizer,
                 mSyncQueue,
-                mDisplayController,
-                mTaskStackListener);
+                mDisplayController);
         mPool = mController.getPool();
         when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
         when(mDisplayController.getDisplay(anyInt())).thenReturn(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
index d3dbbfe..8ece913 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
@@ -24,7 +24,6 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import org.junit.After;
 import org.junit.Before;
@@ -42,7 +41,6 @@
     @Mock private SyncTransactionQueue mSyncQueue;
     @Mock private ShellTaskOrganizer mTaskOrganizer;
     @Mock private DisplayController mDisplayController;
-    @Mock private TaskStackListenerImpl mTaskStackListener;
 
     @Before
     public void setUp() {
@@ -50,8 +48,7 @@
         mController = new TestAppPairsController(
                 mTaskOrganizer,
                 mSyncQueue,
-                mDisplayController,
-                mTaskStackListener);
+                mDisplayController);
         mPool = mController.getPool();
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
index e61cc91..be09636 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
@@ -19,14 +19,13 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
 
 public class TestAppPairsController extends AppPairsController {
     TestAppPairsPool mPool;
 
     public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
-            DisplayController displayController, TaskStackListenerImpl taskStackListener) {
-        super(organizer, syncQueue, displayController, taskStackListener);
+            DisplayController displayController) {
+        super(organizer, syncQueue, displayController);
         mPool = new TestAppPairsPool(this);
         setPairsPool(mPool);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index fad1f05..92d4bee 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -42,7 +42,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.ActivityManager;
-import android.app.IActivityTaskManager;
+import android.app.ActivityTaskManager;
 import android.app.PendingIntent;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -69,7 +69,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
@@ -88,7 +87,7 @@
     private Context mContext;
 
     @Mock
-    private IActivityTaskManager mIActivityTaskManager;
+    private ActivityTaskManager mActivityTaskManager;
 
     @Mock
     private SplitScreen mSplitScreen;
@@ -134,7 +133,7 @@
             return null;
         }).when(mSplitScreen).registerInSplitScreenListener(any());
 
-        mPolicy = new DragAndDropPolicy(mContext, mIActivityTaskManager, mSplitScreen, mStarter);
+        mPolicy = new DragAndDropPolicy(mContext, mActivityTaskManager, mSplitScreen, mStarter);
         mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
         mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
         setClipDataResizeable(mNonResizeableActivityClipData, false);
@@ -188,9 +187,9 @@
         return info;
     }
 
-    private void setRunningTask(ActivityManager.RunningTaskInfo task) throws RemoteException {
-        doReturn(Collections.singletonList(task)).when(mIActivityTaskManager)
-                .getFilteredTasks(anyInt(), anyBoolean());
+    private void setRunningTask(ActivityManager.RunningTaskInfo task) {
+        doReturn(Collections.singletonList(task)).when(mActivityTaskManager)
+                .getTasks(anyInt(), anyBoolean());
     }
 
     private void setClipDataResizeable(ClipData data, boolean resizeable) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java
index 0f719af..fc0e20b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java
@@ -96,6 +96,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 200, 100),
                         /* activityBounds */ new Rect(75, 0, 125, 75),
                         /* taskBounds */ new Rect(50, 0, 125, 100)),
@@ -109,6 +110,7 @@
         mLetterboxTaskListener.onTaskInfoChanged(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 200, 100),
                         // Activity is offset by 25 to the left
                         /* activityBounds */ new Rect(50, 0, 100, 75),
@@ -130,6 +132,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 200, 100),
                         /* activityBounds */ new Rect(150, 0, 200, 75),
                         /* taskBounds */ new Rect(125, 0, 200, 100)),
@@ -150,6 +153,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 200, 100),
                         /* activityBounds */ new Rect(150, 0, 200, 75),
                         /* taskBounds */ new Rect(125, 0, 200, 100)),
@@ -170,6 +174,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 200, 100),
                         /* activityBounds */ new Rect(50, 0, 100, 75),
                         /* taskBounds */ new Rect(25, 0, 100, 100)),
@@ -190,6 +195,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 100, 150),
                         /* activityBounds */ new Rect(0, 75, 50, 125),
                         /* taskBounds */ new Rect(0, 50, 100, 125)),
@@ -210,6 +216,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 100, 150),
                         /* activityBounds */ new Rect(0, 75, 50, 125),
                         /* taskBounds */ new Rect(0, 50, 100, 125)),
@@ -230,6 +237,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 100, 150),
                         /* activityBounds */ new Rect(0, 75, 50, 125),
                         /* taskBounds */ new Rect(0, 50, 100, 125)),
@@ -250,6 +258,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 200, 125), // equal to parent bounds
                         /* parentBounds */ new Rect(0, 0, 200, 125),
                         /* activityBounds */ new Rect(15, 0, 175, 120),
                         /* taskBounds */ new Rect(0, 0, 100, 125)), // equal to parent bounds
@@ -272,6 +281,7 @@
         mLetterboxTaskListener.onTaskAppeared(
                 createTaskInfo(
                         /* taskId */ 1,
+                        /* maxBounds= */ new Rect(0, 0, 100, 150),
                         /* parentBounds */ new Rect(0, 75, 100, 225),
                         /* activityBounds */ new Rect(25, 75, 75, 125),
                         /* taskBounds */ new Rect(0, 75, 100, 125)),
@@ -285,7 +295,7 @@
     public void testOnTaskAppeared_calledSecondTimeWithSameTaskId_throwsException() {
         setWindowBoundsAndInsets(new Rect(),  Insets.NONE);
         RunningTaskInfo taskInfo =
-                createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect());
+                createTaskInfo(/* taskId */ 1, new Rect(),  new Rect(), new Rect(), new Rect());
         mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash);
         mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash);
     }
@@ -306,11 +316,13 @@
 
     private static RunningTaskInfo createTaskInfo(
                 int taskId,
+                final Rect maxBounds,
                 final Rect parentBounds,
                 final Rect activityBounds,
                 final Rect taskBounds) {
         RunningTaskInfo taskInfo = new RunningTaskInfo();
         taskInfo.taskId = taskId;
+        taskInfo.configuration.windowConfiguration.setMaxBounds(maxBounds);
         taskInfo.parentBounds = parentBounds;
         taskInfo.configuration.windowConfiguration.setBounds(taskBounds);
         taskInfo.letterboxActivityBounds = Rect.copyOrNull(activityBounds);
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 8c2a632..a545b3d 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1041,7 +1041,9 @@
 
 base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
   std::vector<uint32_t> found_resids;
-  return GetBag(resid, found_resids);
+  const auto bag = GetBag(resid, found_resids);
+  cached_bag_resid_stacks_.emplace(resid, found_resids);
+  return bag;
 }
 
 base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 4ed5457..cd53217 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -429,6 +429,7 @@
     whole_static_libs: ["libskia"],
 
     srcs: [
+        "canvas/CanvasFrontend.cpp",
         "canvas/CanvasOpBuffer.cpp",
         "canvas/CanvasOpRasterizer.cpp",
         "pipeline/skia/SkiaDisplayList.cpp",
@@ -607,6 +608,7 @@
         "tests/unit/CacheManagerTests.cpp",
         "tests/unit/CanvasContextTests.cpp",
         "tests/unit/CanvasOpTests.cpp",
+        "tests/unit/CanvasFrontendTests.cpp",
         "tests/unit/CommonPoolTests.cpp",
         "tests/unit/DamageAccumulatorTests.cpp",
         "tests/unit/DeferredLayerUpdaterTests.cpp",
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 4981792..c6c4ba8 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -19,7 +19,6 @@
 X(Restore)
 X(SaveLayer)
 X(SaveBehind)
-X(Concat44)
 X(Concat)
 X(SetMatrix)
 X(Scale)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 473dc53d..a495ec4 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -125,24 +125,18 @@
     }
 };
 
-struct Concat44 final : Op {
-    static const auto kType = Type::Concat44;
-    Concat44(const SkM44& m) : matrix(m) {}
-    SkM44 matrix;
-    void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); }
-};
 struct Concat final : Op {
     static const auto kType = Type::Concat;
-    Concat(const SkMatrix& matrix) : matrix(matrix) {}
-    SkMatrix matrix;
+    Concat(const SkM44& matrix) : matrix(matrix) {}
+    SkM44 matrix;
     void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); }
 };
 struct SetMatrix final : Op {
     static const auto kType = Type::SetMatrix;
-    SetMatrix(const SkMatrix& matrix) : matrix(matrix) {}
-    SkMatrix matrix;
+    SetMatrix(const SkM44& matrix) : matrix(matrix) {}
+    SkM44 matrix;
     void draw(SkCanvas* c, const SkMatrix& original) const {
-        c->setMatrix(SkMatrix::Concat(original, matrix));
+        c->setMatrix(SkM44(original) * matrix);
     }
 };
 struct Scale final : Op {
@@ -569,12 +563,9 @@
 }
 
 void DisplayListData::concat(const SkM44& m) {
-    this->push<Concat44>(0, m);
+    this->push<Concat>(0, m);
 }
-void DisplayListData::concat(const SkMatrix& matrix) {
-    this->push<Concat>(0, matrix);
-}
-void DisplayListData::setMatrix(const SkMatrix& matrix) {
+void DisplayListData::setMatrix(const SkM44& matrix) {
     this->push<SetMatrix>(0, matrix);
 }
 void DisplayListData::scale(SkScalar sx, SkScalar sy) {
@@ -834,10 +825,7 @@
 void RecordingCanvas::didConcat44(const SkM44& m) {
     fDL->concat(m);
 }
-void RecordingCanvas::didConcat(const SkMatrix& matrix) {
-    fDL->concat(matrix);
-}
-void RecordingCanvas::didSetMatrix(const SkMatrix& matrix) {
+void RecordingCanvas::didSetM44(const SkM44& matrix) {
     fDL->setMatrix(matrix);
 }
 void RecordingCanvas::didScale(SkScalar sx, SkScalar sy) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 63d120c..4851148 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -82,8 +82,7 @@
     void restore();
 
     void concat(const SkM44&);
-    void concat(const SkMatrix&);
-    void setMatrix(const SkMatrix&);
+    void setMatrix(const SkM44&);
     void scale(SkScalar, SkScalar);
     void translate(SkScalar, SkScalar);
     void translateZ(SkScalar);
@@ -154,8 +153,7 @@
     void onFlush() override;
 
     void didConcat44(const SkM44&) override;
-    void didConcat(const SkMatrix&) override;
-    void didSetMatrix(const SkMatrix&) override;
+    void didSetM44(const SkM44&) override;
     void didScale(SkScalar, SkScalar) override;
     void didTranslate(SkScalar, SkScalar) override;
 
diff --git a/core/proto/android/stats/accessibility/accessibility_enums.proto b/libs/hwui/SaveFlags.h
similarity index 61%
copy from core/proto/android/stats/accessibility/accessibility_enums.proto
copy to libs/hwui/SaveFlags.h
index 5118ad5..f3579a8 100644
--- a/core/proto/android/stats/accessibility/accessibility_enums.proto
+++ b/libs/hwui/SaveFlags.h
@@ -14,22 +14,23 @@
  * limitations under the License.
  */
 
-syntax = "proto2";
-package android.stats.accessibility;
-option java_multiple_files = true;
+#pragma once
 
-// The entry point of the accessibility shortcut.
-enum ShortcutType {
-  UNKNOWN_TYPE = 0;
-  A11Y_BUTTON = 1;
-  VOLUME_KEY = 2;
-  TRIPLE_TAP = 3;
-  A11Y_BUTTON_LONG_PRESS = 4;
-}
+#include <inttypes.h>
 
-// The service status code.
-enum ServiceStatus {
-  UNKNOWN = 0;
-  ENABLED = 1;
-  DISABLED = 2;
-}
\ No newline at end of file
+// TODO: Move this to an enum class
+namespace android::SaveFlags {
+
+// These must match the corresponding Canvas API constants.
+enum {
+    Matrix = 0x01,
+    Clip = 0x02,
+    HasAlphaLayer = 0x04,
+    ClipToLayer = 0x10,
+
+    // Helper constant
+    MatrixClip = Matrix | Clip,
+};
+typedef uint32_t Flags;
+
+}  // namespace android::SaveFlags
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index cd908354..6030c36 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -505,13 +505,11 @@
     SkPaint paint = inPaint;
     paint.setAlpha(mProperties.getRootAlpha() * 255);
 
-    Bitmap& bitmap = getBitmapUpdateIfDirty();
-    SkBitmap skiaBitmap;
-    bitmap.getSkBitmap(&skiaBitmap);
+    sk_sp<SkImage> cachedBitmap = getBitmapUpdateIfDirty().makeImage();
 
     int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
     int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
-    canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
+    canvas->drawImageRect(cachedBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
                            &paint, SkCanvas::kFast_SrcRectConstraint);
 }
 
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 68541b4..671c66f 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -26,6 +26,35 @@
 
 namespace android::uirenderer {
 
+namespace {
+class ScopedCurrentFunctor {
+public:
+    ScopedCurrentFunctor(WebViewFunctor* functor) {
+        ALOG_ASSERT(!sCurrentFunctor);
+        ALOG_ASSERT(functor);
+        sCurrentFunctor = functor;
+    }
+    ~ScopedCurrentFunctor() {
+        ALOG_ASSERT(sCurrentFunctor);
+        sCurrentFunctor = nullptr;
+    }
+
+    static ASurfaceControl* getSurfaceControl() {
+        ALOG_ASSERT(sCurrentFunctor);
+        return sCurrentFunctor->getSurfaceControl();
+    }
+    static void mergeTransaction(ASurfaceTransaction* transaction) {
+        ALOG_ASSERT(sCurrentFunctor);
+        sCurrentFunctor->mergeTransaction(transaction);
+    }
+
+private:
+    static WebViewFunctor* sCurrentFunctor;
+};
+
+WebViewFunctor* ScopedCurrentFunctor::sCurrentFunctor = nullptr;
+}  // namespace
+
 RenderMode WebViewFunctor_queryPlatformRenderMode() {
     auto pipelineType = Properties::getRenderPipelineType();
     switch (pipelineType) {
@@ -83,7 +112,15 @@
     if (!mHasContext) {
         mHasContext = true;
     }
-    mCallbacks.gles.draw(mFunctor, mData, drawInfo);
+    ScopedCurrentFunctor currentFunctor(this);
+
+    WebViewOverlayData overlayParams = {
+            // TODO:
+            .overlaysMode = OverlaysMode::Disabled,
+            .getSurfaceControl = currentFunctor.getSurfaceControl,
+            .mergeTransaction = currentFunctor.mergeTransaction,
+    };
+    mCallbacks.gles.draw(mFunctor, mData, drawInfo, overlayParams);
 }
 
 void WebViewFunctor::initVk(const VkFunctorInitParams& params) {
@@ -98,7 +135,15 @@
 
 void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
     ATRACE_NAME("WebViewFunctor::drawVk");
-    mCallbacks.vk.draw(mFunctor, mData, params);
+    ScopedCurrentFunctor currentFunctor(this);
+
+    WebViewOverlayData overlayParams = {
+            // TODO
+            .overlaysMode = OverlaysMode::Disabled,
+            .getSurfaceControl = currentFunctor.getSurfaceControl,
+            .mergeTransaction = currentFunctor.mergeTransaction,
+    };
+    mCallbacks.vk.draw(mFunctor, mData, params, overlayParams);
 }
 
 void WebViewFunctor::postDrawVk() {
@@ -118,6 +163,20 @@
     }
 }
 
+void WebViewFunctor::removeOverlays() {
+    ScopedCurrentFunctor currentFunctor(this);
+    mCallbacks.removeOverlays(mFunctor, mData, currentFunctor.mergeTransaction);
+}
+
+ASurfaceControl* WebViewFunctor::getSurfaceControl() {
+    // TODO
+    return nullptr;
+}
+
+void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {
+    // TODO
+}
+
 WebViewFunctorManager& WebViewFunctorManager::instance() {
     static WebViewFunctorManager sInstance;
     return sInstance;
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index 675b738..737d605 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -56,6 +56,8 @@
 
         void postDrawVk() { mReference.postDrawVk(); }
 
+        void removeOverlays() { mReference.removeOverlays(); }
+
     private:
         friend class WebViewFunctor;
 
@@ -71,6 +73,10 @@
     void drawVk(const VkFunctorDrawParams& params);
     void postDrawVk();
     void destroyContext();
+    void removeOverlays();
+
+    ASurfaceControl* getSurfaceControl();
+    void mergeTransaction(ASurfaceTransaction* transaction);
 
     sp<Handle> createHandle() {
         LOG_ALWAYS_FATAL_IF(mCreatedHandle);
diff --git a/libs/hwui/canvas/CanvasFrontend.cpp b/libs/hwui/canvas/CanvasFrontend.cpp
new file mode 100644
index 0000000..2c839b0
--- /dev/null
+++ b/libs/hwui/canvas/CanvasFrontend.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanvasFrontend.h"
+#include "CanvasOps.h"
+#include "CanvasOpBuffer.h"
+
+namespace android::uirenderer {
+
+CanvasStateHelper::CanvasStateHelper(int width, int height) {
+    mInitialBounds = SkIRect::MakeWH(width, height);
+    mSaveStack.emplace_back();
+    mClipStack.emplace_back().setRect(mInitialBounds);
+    mTransformStack.emplace_back();
+    mCurrentClipIndex = 0;
+    mCurrentTransformIndex = 0;
+}
+
+bool CanvasStateHelper::internalSave(SaveEntry saveEntry) {
+    mSaveStack.push_back(saveEntry);
+    if (saveEntry.matrix) {
+        // We need to push before accessing transform() to ensure the reference doesn't move
+        // across vector resizes
+        mTransformStack.emplace_back() = transform();
+        mCurrentTransformIndex += 1;
+    }
+    if (saveEntry.clip) {
+        // We need to push before accessing clip() to ensure the reference doesn't move
+        // across vector resizes
+        mClipStack.emplace_back() = clip();
+        mCurrentClipIndex += 1;
+        return true;
+    }
+    return false;
+}
+
+// Assert that the cast from SkClipOp to SkRegion::Op is valid
+static_assert(static_cast<int>(SkClipOp::kDifference) == SkRegion::Op::kDifference_Op);
+static_assert(static_cast<int>(SkClipOp::kIntersect) == SkRegion::Op::kIntersect_Op);
+static_assert(static_cast<int>(SkClipOp::kUnion_deprecated) == SkRegion::Op::kUnion_Op);
+static_assert(static_cast<int>(SkClipOp::kXOR_deprecated) == SkRegion::Op::kXOR_Op);
+static_assert(static_cast<int>(SkClipOp::kReverseDifference_deprecated) == SkRegion::Op::kReverseDifference_Op);
+static_assert(static_cast<int>(SkClipOp::kReplace_deprecated) == SkRegion::Op::kReplace_Op);
+
+void CanvasStateHelper::internalClipRect(const SkRect& rect, SkClipOp op) {
+    clip().opRect(rect, transform(), mInitialBounds, (SkRegion::Op)op, false);
+}
+
+void CanvasStateHelper::internalClipPath(const SkPath& path, SkClipOp op) {
+    clip().opPath(path, transform(), mInitialBounds, (SkRegion::Op)op, true);
+}
+
+bool CanvasStateHelper::internalRestore() {
+    // Prevent underflows
+    if (saveCount() <= 1) {
+        return false;
+    }
+
+    SaveEntry entry = mSaveStack[mSaveStack.size() - 1];
+    mSaveStack.pop_back();
+    bool needsRestorePropagation = entry.layer;
+    if (entry.matrix) {
+        mTransformStack.pop_back();
+        mCurrentTransformIndex -= 1;
+    }
+    if (entry.clip) {
+        // We need to push before accessing clip() to ensure the reference doesn't move
+        // across vector resizes
+        mClipStack.pop_back();
+        mCurrentClipIndex -= 1;
+        needsRestorePropagation = true;
+    }
+    return needsRestorePropagation;
+}
+
+SkRect CanvasStateHelper::getClipBounds() const {
+    SkIRect ibounds = clip().getBounds();
+
+    if (ibounds.isEmpty()) {
+        return SkRect::MakeEmpty();
+    }
+
+    SkMatrix inverse;
+    // if we can't invert the CTM, we can't return local clip bounds
+    if (!transform().invert(&inverse)) {
+        return SkRect::MakeEmpty();
+    }
+
+    SkRect ret = SkRect::MakeEmpty();
+    inverse.mapRect(&ret, SkRect::Make(ibounds));
+    return ret;
+}
+
+bool CanvasStateHelper::quickRejectRect(float left, float top, float right, float bottom) const {
+    // TODO: Implement
+    return false;
+}
+
+bool CanvasStateHelper::quickRejectPath(const SkPath& path) const {
+    // TODO: Implement
+    return false;
+}
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasFrontend.h b/libs/hwui/canvas/CanvasFrontend.h
new file mode 100644
index 0000000..5fccccb
--- /dev/null
+++ b/libs/hwui/canvas/CanvasFrontend.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// TODO: Can we get the dependencies scoped down more?
+#include "CanvasOps.h"
+#include "CanvasOpBuffer.h"
+#include <SaveFlags.h>
+
+#include <SkRasterClip.h>
+#include <ui/FatVector.h>
+
+#include <optional>
+
+namespace android::uirenderer {
+
+// Exists to avoid forcing all this common logic into the templated class
+class CanvasStateHelper {
+protected:
+    CanvasStateHelper(int width, int height);
+    ~CanvasStateHelper() = default;
+
+    struct SaveEntry {
+        bool clip : 1 = false;
+        bool matrix : 1 = false;
+        bool layer : 1 = false;
+    };
+
+    constexpr SaveEntry saveEntryForLayer() {
+        return {
+            .clip = true,
+            .matrix = true,
+            .layer = true,
+        };
+    }
+
+    constexpr SaveEntry flagsToSaveEntry(SaveFlags::Flags flags) {
+        return SaveEntry {
+            .clip = static_cast<bool>(flags & SaveFlags::Clip),
+            .matrix = static_cast<bool>(flags & SaveFlags::Matrix),
+            .layer = false
+        };
+    }
+
+    bool internalSave(SaveEntry saveEntry);
+    bool internalSave(SaveFlags::Flags flags) {
+        return internalSave(flagsToSaveEntry(flags));
+    }
+    void internalSaveLayer(const SkCanvas::SaveLayerRec& layerRec) {
+        internalSave({
+            .clip = true,
+            .matrix = true,
+            .layer = true
+        });
+        internalClipRect(*layerRec.fBounds, SkClipOp::kIntersect);
+    }
+
+    bool internalRestore();
+
+    void internalClipRect(const SkRect& rect, SkClipOp op);
+    void internalClipPath(const SkPath& path, SkClipOp op);
+
+    SkIRect mInitialBounds;
+    FatVector<SaveEntry, 6> mSaveStack;
+    FatVector<SkMatrix, 6> mTransformStack;
+    FatVector<SkConservativeClip, 6> mClipStack;
+
+    size_t mCurrentTransformIndex;
+    size_t mCurrentClipIndex;
+
+    const SkConservativeClip& clip() const {
+        return mClipStack[mCurrentClipIndex];
+    }
+
+    SkConservativeClip& clip() {
+        return mClipStack[mCurrentClipIndex];
+    }
+
+public:
+    int saveCount() const { return mSaveStack.size(); }
+
+    SkRect getClipBounds() const;
+    bool quickRejectRect(float left, float top, float right, float bottom) const;
+    bool quickRejectPath(const SkPath& path) const;
+
+    const SkMatrix& transform() const {
+        return mTransformStack[mCurrentTransformIndex];
+    }
+
+    SkMatrix& transform() {
+        return mTransformStack[mCurrentTransformIndex];
+    }
+
+    // For compat with existing HWUI Canvas interface
+    void getMatrix(SkMatrix* outMatrix) const {
+        *outMatrix = transform();
+    }
+
+    void setMatrix(const SkMatrix& matrix) {
+        transform() = matrix;
+    }
+
+    void concat(const SkMatrix& matrix) {
+        transform().preConcat(matrix);
+    }
+
+    void rotate(float degrees) {
+        SkMatrix m;
+        m.setRotate(degrees);
+        concat(m);
+    }
+
+    void scale(float sx, float sy) {
+        SkMatrix m;
+        m.setScale(sx, sy);
+        concat(m);
+    }
+
+    void skew(float sx, float sy) {
+        SkMatrix m;
+        m.setSkew(sx, sy);
+        concat(m);
+    }
+
+    void translate(float dx, float dy) {
+        transform().preTranslate(dx, dy);
+    }
+};
+
+// Front-end canvas that handles queries, up-front state, and produces CanvasOp<> output downstream
+template <typename CanvasOpReceiver>
+class CanvasFrontend final : public CanvasStateHelper {
+public:
+    template<class... Args>
+    CanvasFrontend(int width, int height, Args&&... args) : CanvasStateHelper(width, height),
+            mReceiver(std::forward<Args>(args)...) { }
+    ~CanvasFrontend() = default;
+
+    void save(SaveFlags::Flags flags = SaveFlags::MatrixClip) {
+        if (internalSave(flagsToSaveEntry(flags))) {
+            submit<CanvasOpType::Save>({});
+        }
+    }
+
+    void restore() {
+        if (internalRestore()) {
+            submit<CanvasOpType::Restore>({});
+        }
+    }
+
+    template <CanvasOpType T>
+    void draw(CanvasOp<T>&& op) {
+        // The front-end requires going through certain front-doors, which these aren't.
+        static_assert(T != CanvasOpType::Save, "Must use CanvasFrontend::save() call instead");
+        static_assert(T != CanvasOpType::Restore, "Must use CanvasFrontend::restore() call instead");
+
+        if constexpr (T == CanvasOpType::SaveLayer) {
+            internalSaveLayer(op.saveLayerRec);
+        }
+        if constexpr (T == CanvasOpType::SaveBehind) {
+            // Don't use internalSaveLayer as this doesn't apply clipping, it's a "regular" save
+            // But we do want to flag it as a layer, such that restore is Definitely Required
+            internalSave(saveEntryForLayer());
+        }
+        if constexpr (T == CanvasOpType::ClipRect) {
+            internalClipRect(op.rect, op.op);
+        }
+        if constexpr (T == CanvasOpType::ClipPath) {
+            internalClipPath(op.path, op.op);
+        }
+
+        submit(std::move(op));
+    }
+
+    const CanvasOpReceiver& receiver() const { return mReceiver; }
+
+private:
+    CanvasOpReceiver mReceiver;
+
+    template <CanvasOpType T>
+    void submit(CanvasOp<T>&& op) {
+        mReceiver.push_container(CanvasOpContainer(std::move(op), transform()));
+    }
+};
+
+} // namespace android::uirenderer
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt b/libs/hwui/canvas/CanvasOpRecorder.cpp
similarity index 79%
copy from tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
copy to libs/hwui/canvas/CanvasOpRecorder.cpp
index 6bc9dcb..bb968ee8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
+++ b/libs/hwui/canvas/CanvasOpRecorder.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+#include "CanvasOpRecorder.h"
 
-internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
+#include "CanvasOpBuffer.h"
+#include "CanvasOps.h"
+
+namespace android::uirenderer {}  // namespace android::uirenderer
diff --git a/core/proto/android/stats/accessibility/accessibility_enums.proto b/libs/hwui/canvas/CanvasOpRecorder.h
similarity index 62%
rename from core/proto/android/stats/accessibility/accessibility_enums.proto
rename to libs/hwui/canvas/CanvasOpRecorder.h
index 5118ad5..7d95bc4 100644
--- a/core/proto/android/stats/accessibility/accessibility_enums.proto
+++ b/libs/hwui/canvas/CanvasOpRecorder.h
@@ -14,22 +14,25 @@
  * limitations under the License.
  */
 
-syntax = "proto2";
-package android.stats.accessibility;
-option java_multiple_files = true;
+#pragma once
 
-// The entry point of the accessibility shortcut.
-enum ShortcutType {
-  UNKNOWN_TYPE = 0;
-  A11Y_BUTTON = 1;
-  VOLUME_KEY = 2;
-  TRIPLE_TAP = 3;
-  A11Y_BUTTON_LONG_PRESS = 4;
-}
+#include "hwui/Canvas.h"
+#include "CanvasOpBuffer.h"
 
-// The service status code.
-enum ServiceStatus {
-  UNKNOWN = 0;
-  ENABLED = 1;
-  DISABLED = 2;
-}
\ No newline at end of file
+#include <vector>
+
+namespace android::uirenderer {
+
+// Interop with existing HWUI Canvas
+class CanvasOpRecorder final : /* todo: public Canvas */ {
+public:
+    // Transform ops
+private:
+    struct SaveEntry {
+
+    };
+
+    std::vector<SaveEntry> mSaveStack;
+};
+
+}  // namespace android::uirenderer
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index f94bae2..4d67166 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -18,6 +18,7 @@
 
 #include <cutils/compiler.h>
 #include <utils/Functor.h>
+#include <SaveFlags.h>
 
 #include <androidfw/ResourceTypes.h>
 #include "Properties.h"
@@ -57,22 +58,6 @@
 using DisplayList = skiapipeline::SkiaDisplayList;
 }
 
-namespace SaveFlags {
-
-// These must match the corresponding Canvas API constants.
-enum {
-    Matrix = 0x01,
-    Clip = 0x02,
-    HasAlphaLayer = 0x04,
-    ClipToLayer = 0x10,
-
-    // Helper constant
-    MatrixClip = Matrix | Clip,
-};
-typedef uint32_t Flags;
-
-}  // namespace SaveFlags
-
 namespace uirenderer {
 namespace VectorDrawable {
 class Tree;
diff --git a/libs/hwui/jni/pdf/PdfEditor.cpp b/libs/hwui/jni/pdf/PdfEditor.cpp
index e65921a..427bafa 100644
--- a/libs/hwui/jni/pdf/PdfEditor.cpp
+++ b/libs/hwui/jni/pdf/PdfEditor.cpp
@@ -129,8 +129,8 @@
 
     // PDF's coordinate system origin is left-bottom while in graphics it
     // is the top-left. So, translate the PDF coordinates to ours.
-    SkMatrix reflectOnX = SkMatrix::MakeScale(1, -1);
-    SkMatrix moveUp = SkMatrix::MakeTrans(0, FPDF_GetPageHeight(page));
+    SkMatrix reflectOnX = SkMatrix::Scale(1, -1);
+    SkMatrix moveUp = SkMatrix::Translate(0, FPDF_GetPageHeight(page));
     SkMatrix coordinateChange = SkMatrix::Concat(moveUp, reflectOnX);
 
     // Apply the transformation what was created in our coordinates.
diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h
index 96da947..22ae59e 100644
--- a/libs/hwui/private/hwui/WebViewFunctor.h
+++ b/libs/hwui/private/hwui/WebViewFunctor.h
@@ -17,6 +17,15 @@
 #ifndef FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
 #define FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
 
+#ifdef __ANDROID__  // Layoutlib does not support surface control
+#include <android/surface_control.h>
+#else
+// To avoid ifdefs around overlay implementation all over the place we typedef these to void *. They
+// won't be used.
+typedef void* ASurfaceControl;
+typedef void* ASurfaceTransaction;
+#endif
+
 #include <cutils/compiler.h>
 #include <private/hwui/DrawGlInfo.h>
 #include <private/hwui/DrawVkInfo.h>
@@ -28,6 +37,14 @@
     Vulkan,
 };
 
+enum class OverlaysMode {
+    // Indicated that webview should not promote anything to overlays this draw
+    // and remove all visible overlays.
+    Disabled,
+    // Indicates that webview can use overlays.
+    Enabled
+};
+
 // Static for the lifetime of the process
 ANDROID_API RenderMode WebViewFunctor_queryPlatformRenderMode();
 
@@ -35,6 +52,23 @@
     bool applyForceDark;
 };
 
+struct WebViewOverlayData {
+    // Desired overlay mode for this draw.
+    OverlaysMode overlaysMode;
+
+    // Returns parent ASurfaceControl for WebView overlays. It will be have same
+    // geometry as the surface we draw into and positioned below it (underlay).
+    // This does not pass ownership to webview, but guaranteed to be alive until
+    // transaction from next removeOverlays call or functor destruction will be
+    // finished.
+    ASurfaceControl* (*getSurfaceControl)();
+
+    // Merges WebView transaction to be applied synchronously with current draw.
+    // This doesn't pass ownership of the transaction, changes will be copied and
+    // webview can free transaction right after the call.
+    void (*mergeTransaction)(ASurfaceTransaction*);
+};
+
 struct WebViewFunctorCallbacks {
     // kModeSync, called on RenderThread
     void (*onSync)(int functor, void* data, const WebViewSyncData& syncData);
@@ -48,16 +82,23 @@
     // this functor had ever been drawn.
     void (*onDestroyed)(int functor, void* data);
 
+    // Called on render thread to force webview hide all overlays and stop updating them.
+    // Should happen during hwui draw (e.g can be called instead of draw if webview
+    // isn't visible and won't receive draw) and support MergeTransaction call.
+    void (*removeOverlays)(int functor, void* data, void (*mergeTransaction)(ASurfaceTransaction*));
+
     union {
         struct {
             // Called on RenderThread. initialize is guaranteed to happen before this call
-            void (*draw)(int functor, void* data, const DrawGlInfo& params);
+            void (*draw)(int functor, void* data, const DrawGlInfo& params,
+                         const WebViewOverlayData& overlayParams);
         } gles;
         struct {
             // Called either the first time the functor is used or the first time it's used after
             // a call to onContextDestroyed.
             void (*initialize)(int functor, void* data, const VkFunctorInitParams& params);
-            void (*draw)(int functor, void* data, const VkFunctorDrawParams& params);
+            void (*draw)(int functor, void* data, const VkFunctorDrawParams& params,
+                         const WebViewOverlayData& overlayParams);
             void (*postDraw)(int functor, void*);
         } vk;
     };
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 36c5a8c1..c1d8b76 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -323,7 +323,8 @@
         };
         switch (mode) {
             case RenderMode::OpenGL_ES:
-                callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params) {
+                callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params,
+                                         const WebViewOverlayData& overlay_params) {
                     expectOnRenderThread("draw");
                     sMockFunctorCounts[functor].glesDraw++;
                 };
diff --git a/libs/hwui/tests/unit/CanvasFrontendTests.cpp b/libs/hwui/tests/unit/CanvasFrontendTests.cpp
new file mode 100644
index 0000000..05b1179
--- /dev/null
+++ b/libs/hwui/tests/unit/CanvasFrontendTests.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <canvas/CanvasFrontend.h>
+#include <canvas/CanvasOpBuffer.h>
+#include <canvas/CanvasOps.h>
+#include <canvas/CanvasOpRasterizer.h>
+
+#include <tests/common/CallCountingCanvas.h>
+
+#include "SkPictureRecorder.h"
+#include "SkColor.h"
+#include "SkLatticeIter.h"
+#include "pipeline/skia/AnimatedDrawables.h"
+#include <SkNoDrawCanvas.h>
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::test;
+
+class CanvasOpCountingReceiver {
+public:
+    template <CanvasOpType T>
+    void push_container(CanvasOpContainer<T>&& op) {
+        mOpCounts[static_cast<size_t>(T)] += 1;
+    }
+
+    int operator[](CanvasOpType op) const {
+        return mOpCounts[static_cast<size_t>(op)];
+    }
+
+private:
+    std::array<int, static_cast<size_t>(CanvasOpType::COUNT)> mOpCounts;
+};
+
+TEST(CanvasFrontend, saveCount) {
+    SkNoDrawCanvas skiaCanvas(100, 100);
+    CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
+    const auto& receiver = opCanvas.receiver();
+
+    EXPECT_EQ(1, skiaCanvas.getSaveCount());
+    EXPECT_EQ(1, opCanvas.saveCount());
+
+    skiaCanvas.save();
+    opCanvas.save(SaveFlags::MatrixClip);
+    EXPECT_EQ(2, skiaCanvas.getSaveCount());
+    EXPECT_EQ(2, opCanvas.saveCount());
+
+    skiaCanvas.restore();
+    opCanvas.restore();
+    EXPECT_EQ(1, skiaCanvas.getSaveCount());
+    EXPECT_EQ(1, opCanvas.saveCount());
+
+    skiaCanvas.restore();
+    opCanvas.restore();
+    EXPECT_EQ(1, skiaCanvas.getSaveCount());
+    EXPECT_EQ(1, opCanvas.saveCount());
+
+    EXPECT_EQ(1, receiver[CanvasOpType::Save]);
+    EXPECT_EQ(1, receiver[CanvasOpType::Restore]);
+}
+
+TEST(CanvasFrontend, transform) {
+    SkNoDrawCanvas skiaCanvas(100, 100);
+    CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
+
+    skiaCanvas.translate(10, 10);
+    opCanvas.translate(10, 10);
+    EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+
+    {
+        skiaCanvas.save();
+        opCanvas.save(SaveFlags::Matrix);
+        skiaCanvas.scale(2.0f, 1.125f);
+        opCanvas.scale(2.0f, 1.125f);
+
+        EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+        skiaCanvas.restore();
+        opCanvas.restore();
+    }
+
+    EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+
+    {
+        skiaCanvas.save();
+        opCanvas.save(SaveFlags::Matrix);
+        skiaCanvas.rotate(90.f);
+        opCanvas.rotate(90.f);
+
+        EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+
+        {
+            skiaCanvas.save();
+            opCanvas.save(SaveFlags::Matrix);
+            skiaCanvas.skew(5.0f, 2.25f);
+            opCanvas.skew(5.0f, 2.25f);
+
+            EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+            skiaCanvas.restore();
+            opCanvas.restore();
+        }
+
+        skiaCanvas.restore();
+        opCanvas.restore();
+    }
+
+    EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+}
+
+TEST(CanvasFrontend, drawOpTransform) {
+    CanvasFrontend<CanvasOpBuffer> opCanvas(100, 100);
+    const auto& receiver = opCanvas.receiver();
+
+    auto makeDrawRect = [] {
+        return CanvasOp<CanvasOpType::DrawRect>{
+            .rect = SkRect::MakeWH(50, 50),
+            .paint = SkPaint(SkColors::kBlack),
+        };
+    };
+
+    opCanvas.draw(makeDrawRect());
+
+    opCanvas.translate(10, 10);
+    opCanvas.draw(makeDrawRect());
+
+    opCanvas.save();
+    opCanvas.scale(2.0f, 4.0f);
+    opCanvas.draw(makeDrawRect());
+    opCanvas.restore();
+
+    opCanvas.save();
+    opCanvas.translate(20, 15);
+    opCanvas.draw(makeDrawRect());
+    opCanvas.save();
+    opCanvas.rotate(90.f);
+    opCanvas.draw(makeDrawRect());
+    opCanvas.restore();
+    opCanvas.restore();
+
+    // Validate the results
+    std::vector<SkMatrix> transforms;
+    transforms.reserve(5);
+    receiver.for_each([&](auto op) {
+        // Filter for the DrawRect calls; ignore the save & restores
+        // (TODO: Add a filtered for_each variant to OpBuffer?)
+        if (op->type() == CanvasOpType::DrawRect) {
+            transforms.push_back(op->transform());
+        }
+    });
+
+    EXPECT_EQ(transforms.size(), 5);
+
+    {
+        // First result should be identity
+        const auto& result = transforms[0];
+        EXPECT_EQ(SkMatrix::kIdentity_Mask, result.getType());
+        EXPECT_EQ(SkMatrix::I(), result);
+    }
+
+    {
+        // Should be translate 10, 10
+        const auto& result = transforms[1];
+        EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
+        SkMatrix m;
+        m.setTranslate(10, 10);
+        EXPECT_EQ(m, result);
+    }
+
+    {
+        // Should be translate 10, 10 + scale 2, 4
+        const auto& result = transforms[2];
+        EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask, result.getType());
+        SkMatrix m;
+        m.setTranslate(10, 10);
+        m.preScale(2.0f, 4.0f);
+        EXPECT_EQ(m, result);
+    }
+
+    {
+        // Should be translate 10, 10 + translate 20, 15
+        const auto& result = transforms[3];
+        EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
+        SkMatrix m;
+        m.setTranslate(30, 25);
+        EXPECT_EQ(m, result);
+    }
+
+    {
+        // Should be translate 10, 10 + translate 20, 15 + rotate 90
+        const auto& result = transforms[4];
+        EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask,
+                result.getType());
+        SkMatrix m;
+        m.setTranslate(30, 25);
+        m.preRotate(90.f);
+        EXPECT_EQ(m, result);
+    }
+}
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index b15c322..f186e55 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -16,6 +16,7 @@
 
 #include <gtest/gtest.h>
 
+#include <canvas/CanvasFrontend.h>
 #include <canvas/CanvasOpBuffer.h>
 #include <canvas/CanvasOps.h>
 #include <canvas/CanvasOpRasterizer.h>
@@ -26,6 +27,7 @@
 #include "SkColor.h"
 #include "SkLatticeIter.h"
 #include "pipeline/skia/AnimatedDrawables.h"
+#include <SkNoDrawCanvas.h>
 
 using namespace android;
 using namespace android::uirenderer;
@@ -78,6 +80,21 @@
 
 using MockBuffer = OpBuffer<MockTypes, MockOpContainer>;
 
+class CanvasOpCountingReceiver {
+public:
+    template <CanvasOpType T>
+    void push_container(CanvasOpContainer<T>&& op) {
+        mOpCounts[static_cast<size_t>(T)] += 1;
+    }
+
+    int operator[](CanvasOpType op) const {
+        return mOpCounts[static_cast<size_t>(op)];
+    }
+
+private:
+    std::array<int, static_cast<size_t>(CanvasOpType::COUNT)> mOpCounts;
+};
+
 template<typename T>
 static int countItems(const T& t) {
     int count = 0;
@@ -614,4 +631,35 @@
     rasterizer.draw(op);
     EXPECT_EQ(1, canvas->drawRectCount);
     EXPECT_EQ(1, canvas->sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, frontendSaveCount) {
+    SkNoDrawCanvas skiaCanvas(100, 100);
+    CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
+    const auto& receiver = opCanvas.receiver();
+
+    EXPECT_EQ(1, skiaCanvas.getSaveCount());
+    EXPECT_EQ(1, opCanvas.saveCount());
+
+    skiaCanvas.save();
+    opCanvas.save(SaveFlags::MatrixClip);
+    EXPECT_EQ(2, skiaCanvas.getSaveCount());
+    EXPECT_EQ(2, opCanvas.saveCount());
+
+    skiaCanvas.restore();
+    opCanvas.restore();
+    EXPECT_EQ(1, skiaCanvas.getSaveCount());
+    EXPECT_EQ(1, opCanvas.saveCount());
+
+    skiaCanvas.restore();
+    opCanvas.restore();
+    EXPECT_EQ(1, skiaCanvas.getSaveCount());
+    EXPECT_EQ(1, opCanvas.saveCount());
+
+    EXPECT_EQ(1, receiver[Op::Save]);
+    EXPECT_EQ(1, receiver[Op::Restore]);
+}
+
+TEST(CanvasOp, frontendTransform) {
+
 }
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp
index da6a260..bffdeca 100644
--- a/libs/hwui/tests/unit/CommonPoolTests.cpp
+++ b/libs/hwui/tests/unit/CommonPoolTests.cpp
@@ -54,7 +54,9 @@
     EXPECT_EQ(0, threads.count(gettid()));
 }
 
-TEST(CommonPool, singleThread) {
+// Disabled since this is flaky. This isn't a necessarily useful functional test, so being
+// disabled isn't that significant. However it may be good to resurrect this somehow.
+TEST(CommonPool, DISABLED_singleThread) {
     std::mutex mutex;
     std::condition_variable fence;
     bool isProcessing = false;
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index f4c3e13..955a5e7 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -39,7 +39,7 @@
     EXPECT_EQ(Matrix4::identity(), layerUpdater->backingLayer()->getTexTransform());
 
     // push the deferred updates to the layer
-    SkMatrix scaledMatrix = SkMatrix::MakeScale(0.5, 0.5);
+    SkMatrix scaledMatrix = SkMatrix::Scale(0.5, 0.5);
     SkBitmap bitmap;
     bitmap.allocN32Pixels(16, 16);
     sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap);
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index abdf9d5..26bc659 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -206,7 +206,7 @@
                 ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
 
                 recorder.translate(300.0f, 400.0f);
-                EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
+                EXPECT_EQ(SkMatrix::Translate(300.0f, 400.0f), getRecorderMatrix(recorder));
 
                 recorder.restore();
                 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
@@ -1107,27 +1107,27 @@
             EXPECT_EQ(dy, TRANSLATE_Y);
         }
 
-        virtual void didSetMatrix(const SkMatrix& matrix) override {
+        virtual void didSetM44(const SkM44& matrix) override {
             mDrawCounter++;
             // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
             // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
-            EXPECT_TRUE(matrix.isIdentity());
+            EXPECT_TRUE(matrix == SkM44());
             EXPECT_TRUE(getTotalMatrix().isIdentity());
         }
 
-        virtual void didConcat(const SkMatrix& matrix) override {
+        virtual void didConcat44(const SkM44& matrix) override {
             mDrawCounter++;
             if (mFirstDidConcat) {
                 // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
                 mFirstDidConcat = false;
-                EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
+                EXPECT_EQ(SkM44::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
                           matrix);
-                EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
+                EXPECT_EQ(SkMatrix::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
                           getTotalMatrix());
             } else {
                 // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
-                EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), matrix);
-                EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix());
+                EXPECT_EQ(SkM44::Translate(TRANSLATE_X, TRANSLATE_Y), matrix);
+                EXPECT_EQ(SkMatrix::Translate(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix());
             }
         }
 
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index c19e1ed..4659a92 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -264,6 +264,8 @@
     TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) {
         TestUtils::syncHierarchyPropertiesAndDisplayList(node);
     });
+    // Fence on any remaining post'd work
+    TestUtils::runOnRenderThreadUnmanaged([] (RenderThread&) {});
     EXPECT_EQ(2, counts.sync);
     EXPECT_EQ(1, counts.destroyed);
 }
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 74a5654..2d34b09 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -263,10 +263,10 @@
     }
 
     // Another way to be offscreen: a matrix from the draw call.
-    for (const SkMatrix translate : { SkMatrix::MakeTrans(width, 0),
-                                      SkMatrix::MakeTrans(0, height),
-                                      SkMatrix::MakeTrans(-width, 0),
-                                      SkMatrix::MakeTrans(0, -height)}) {
+    for (const SkMatrix translate : { SkMatrix::Translate(width, 0),
+                                      SkMatrix::Translate(0, height),
+                                      SkMatrix::Translate(-width, 0),
+                                      SkMatrix::Translate(0, -height)}) {
         SkiaDisplayList skiaDL;
         VectorDrawableRoot dirtyVD(new VectorDrawable::Group());
         dirtyVD.mutateProperties()->setBounds(bounds);
@@ -291,7 +291,7 @@
         SkiaDisplayList skiaDL;
         VectorDrawableRoot dirtyVD(new VectorDrawable::Group());
         dirtyVD.mutateProperties()->setBounds(bounds);
-        SkMatrix translate = SkMatrix::MakeTrans(50, 50);
+        SkMatrix translate = SkMatrix::Translate(50, 50);
         skiaDL.appendVD(&dirtyVD, translate);
 
         ASSERT_TRUE(dirtyVD.isDirty());
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index eec25c6..15ecf58 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -111,11 +111,11 @@
             [](RenderProperties& properties) {
                 properties.setLeftTopRightBottom(10, 10, 110, 110);
 
-                SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
+                SkMatrix staticMatrix = SkMatrix::Scale(1.2f, 1.2f);
                 properties.setStaticMatrix(&staticMatrix);
 
                 // ignored, since static overrides animation
-                SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
+                SkMatrix animationMatrix = SkMatrix::Translate(15, 15);
                 properties.setAnimationMatrix(&animationMatrix);
 
                 properties.setTranslationX(10);
diff --git a/location/java/com/android/internal/location/timezone/ILocationTimeZoneProviderManager.aidl b/location/java/com/android/internal/location/timezone/ILocationTimeZoneProviderManager.aidl
index f89a64f..b5450b7 100644
--- a/location/java/com/android/internal/location/timezone/ILocationTimeZoneProviderManager.aidl
+++ b/location/java/com/android/internal/location/timezone/ILocationTimeZoneProviderManager.aidl
@@ -16,7 +16,7 @@
 
 package com.android.internal.location.timezone;
 
-import android.location.timezone.LocationTimeZoneEvent;
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
 
 /**
  * Binder interface for the manager of location time zone provider implementations.
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl b/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl
similarity index 92%
rename from location/java/android/location/timezone/LocationTimeZoneEvent.aidl
rename to location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl
index 5386588..199e067 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl
+++ b/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.location.timezone;
+package com.android.internal.location.timezone;
 
 parcelable LocationTimeZoneEvent;
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.java b/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.java
similarity index 86%
rename from location/java/android/location/timezone/LocationTimeZoneEvent.java
rename to location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.java
index 922a389..31c27d1 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.java
+++ b/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.location.timezone;
+package com.android.internal.location.timezone;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -24,6 +24,7 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -70,30 +71,30 @@
     @NonNull
     private final List<String> mTimeZoneIds;
 
-    private final long mElapsedRealtimeNanos;
+    private final long mElapsedRealtimeMillis;
 
     private LocationTimeZoneEvent(@EventType int eventType, @NonNull List<String> timeZoneIds,
-            long elapsedRealtimeNanos) {
+            long elapsedRealtimeMillis) {
         mEventType = checkValidEventType(eventType);
         mTimeZoneIds = immutableList(timeZoneIds);
 
         boolean emptyTimeZoneIdListExpected = eventType != EVENT_TYPE_SUCCESS;
         Preconditions.checkState(!emptyTimeZoneIdListExpected || timeZoneIds.isEmpty());
 
-        mElapsedRealtimeNanos = elapsedRealtimeNanos;
+        mElapsedRealtimeMillis = elapsedRealtimeMillis;
     }
 
     /**
      * Returns the time of this fix, in elapsed real-time since system boot.
      *
      * <p>This value can be reliably compared to {@link
-     * android.os.SystemClock#elapsedRealtimeNanos}, to calculate the age of a fix and to compare
+     * android.os.SystemClock#elapsedRealtime()}, to calculate the age of a fix and to compare
      * {@link LocationTimeZoneEvent} instances.
      *
-     * @return elapsed real-time of fix, in nanoseconds since system boot.
+     * @return elapsed real-time of fix, in milliseconds
      */
-    public long getElapsedRealtimeNanos() {
-        return mElapsedRealtimeNanos;
+    public long getElapsedRealtimeMillis() {
+        return mElapsedRealtimeMillis;
     }
 
     /**
@@ -118,7 +119,8 @@
         return "LocationTimeZoneEvent{"
                 + "mEventType=" + mEventType
                 + ", mTimeZoneIds=" + mTimeZoneIds
-                + ", mElapsedRealtimeNanos=" + mElapsedRealtimeNanos
+                + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
+                + "(" + Duration.ofMillis(mElapsedRealtimeMillis) + ")"
                 + '}';
     }
 
@@ -130,8 +132,8 @@
                     @SuppressWarnings("unchecked")
                     ArrayList<String> timeZoneIds =
                             (ArrayList<String>) in.readArrayList(null /* classLoader */);
-                    long elapsedRealtimeNanos = in.readLong();
-                    return new LocationTimeZoneEvent(eventType, timeZoneIds, elapsedRealtimeNanos);
+                    long elapsedRealtimeMillis = in.readLong();
+                    return new LocationTimeZoneEvent(eventType, timeZoneIds, elapsedRealtimeMillis);
                 }
 
                 @Override
@@ -149,7 +151,7 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mEventType);
         parcel.writeList(mTimeZoneIds);
-        parcel.writeLong(mElapsedRealtimeNanos);
+        parcel.writeLong(mElapsedRealtimeMillis);
     }
 
     @Override
@@ -162,13 +164,13 @@
         }
         LocationTimeZoneEvent that = (LocationTimeZoneEvent) o;
         return mEventType == that.mEventType
-                && mElapsedRealtimeNanos == that.mElapsedRealtimeNanos
+                && mElapsedRealtimeMillis == that.mElapsedRealtimeMillis
                 && mTimeZoneIds.equals(that.mTimeZoneIds);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
+        return Objects.hash(mEventType, mTimeZoneIds, mElapsedRealtimeMillis);
     }
 
     /** @hide */
@@ -176,7 +178,7 @@
 
         private @EventType int mEventType = EVENT_TYPE_UNKNOWN;
         private @NonNull List<String> mTimeZoneIds = Collections.emptyList();
-        private long mElapsedRealtimeNanos;
+        private long mElapsedRealtimeMillis;
 
         public Builder() {
         }
@@ -187,7 +189,7 @@
         public Builder(@NonNull LocationTimeZoneEvent ltz) {
             mEventType = ltz.mEventType;
             mTimeZoneIds = ltz.mTimeZoneIds;
-            mElapsedRealtimeNanos = ltz.mElapsedRealtimeNanos;
+            mElapsedRealtimeMillis = ltz.mElapsedRealtimeMillis;
         }
 
         /**
@@ -210,8 +212,8 @@
         /**
          * Sets the time of this event, in elapsed real-time since system boot.
          */
-        public Builder setElapsedRealtimeNanos(long time) {
-            mElapsedRealtimeNanos = time;
+        public Builder setElapsedRealtimeMillis(long time) {
+            mElapsedRealtimeMillis = time;
             return this;
         }
 
@@ -219,7 +221,7 @@
          * Builds a {@link LocationTimeZoneEvent} instance.
          */
         public LocationTimeZoneEvent build() {
-            return new LocationTimeZoneEvent(mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
+            return new LocationTimeZoneEvent(mEventType, mTimeZoneIds, mElapsedRealtimeMillis);
         }
     }
 
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
index 0739633..55f5545 100644
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
+++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
@@ -18,9 +18,10 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.os.SystemClock;
 
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -146,7 +147,7 @@
             LocationTimeZoneEvent event = new LocationTimeZoneEvent.Builder()
                     .setEventType(internalEventType)
                     .setTimeZoneIds(mTimeZoneIds)
-                    .setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos())
+                    .setElapsedRealtimeMillis(SystemClock.elapsedRealtime())
                     .build();
             return new LocationTimeZoneEventUnbundled(event);
         }
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 65e6fea..ea691a7 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -166,6 +166,7 @@
     //--------------------
     /**
      * Accessed by native methods: provides access to C++ AudioRecord object
+     * Is 0 after release()
      */
     @SuppressWarnings("unused")
     @UnsupportedAppUsage
@@ -1872,7 +1873,11 @@
         if (mNativeRecorderInJavaObj == 0) {
             return 0;
         }
-        return native_getPortId();
+        try {
+            return native_getPortId();
+        } catch (IllegalStateException e) {
+            return 0;
+        }
     }
 
     //--------------------------------------------------------------------------
@@ -2055,6 +2060,9 @@
     private native final int native_get_active_microphones(
             ArrayList<MicrophoneInfo> activeMicrophones);
 
+    /**
+     * @throws IllegalStateException
+     */
     private native int native_getPortId();
 
     private native int native_set_preferred_microphone_direction(int direction);
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index 4544d04..705da19 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -29,6 +29,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.system.Os;
 import android.util.Log;
 
@@ -616,15 +617,24 @@
         /* Writes the TranscodingRequest to a parcel. */
         private TranscodingRequestParcel writeToParcel(@NonNull Context context) {
             TranscodingRequestParcel parcel = new TranscodingRequestParcel();
-            // TODO(hkuang): Implement all the fields here to pass to service.
             parcel.priority = mPriority;
             parcel.transcodingType = mType;
             parcel.sourceFilePath = mSourceUri.toString();
             parcel.destinationFilePath = mDestinationUri.toString();
             parcel.clientUid = mClientUid;
             parcel.clientPid = mClientPid;
-            parcel.clientPackageName = mClientUid < 0 ? context.getPackageName() :
-                context.getPackageManager().getNameForUid(mClientUid);
+            if (mClientUid < 0) {
+                parcel.clientPackageName = context.getPackageName();
+            } else {
+                String packageName = context.getPackageManager().getNameForUid(mClientUid);
+                // PackageName is optional as some uid does not have package name. Set to
+                // "Unavailable" string in this case.
+                if (packageName == null) {
+                    Log.w(TAG, "Failed to find package for uid: " + mClientUid);
+                    packageName = "Unavailable";
+                }
+                parcel.clientPackageName = packageName;
+            }
             parcel.requestedVideoTrackFormat = convertToVideoTrackFormat(mVideoTrackFormat);
             if (mTestConfig != null) {
                 parcel.isForTesting = true;
@@ -753,7 +763,7 @@
              */
             @NonNull
             public Builder setClientUid(int uid) {
-                if (uid <= 0) {
+                if (uid < 0) {
                     throw new IllegalArgumentException("Invalid Uid");
                 }
                 mClientUid = uid;
@@ -769,7 +779,7 @@
              */
             @NonNull
             public Builder setClientPid(int pid) {
-                if (pid <= 0) {
+                if (pid < 0) {
                     throw new IllegalArgumentException("Invalid pid");
                 }
                 mClientPid = pid;
@@ -1417,7 +1427,7 @@
                 mPendingTranscodingSessions.put(session.getSessionId(), session);
                 return session;
             }
-        } catch (RemoteException re) {
+        } catch (RemoteException | ServiceSpecificException ex) {
             throw new UnsupportedOperationException(
                     "Failed to submit request to Transcoding service");
         }
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
index be75258..4da23a1 100644
--- a/media/java/android/media/Rating.java
+++ b/media/java/android/media/Rating.java
@@ -206,11 +206,12 @@
                 Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
                 return null;
         }
-        if ((starRating < 0.0f) || (starRating > maxRating)) {
+        if (starRating >= 0.0f && starRating <= maxRating) {
+            return new Rating(starRatingStyle, starRating);
+        } else {
             Log.e(TAG, "Trying to set out of range star-based rating");
             return null;
         }
-        return new Rating(starRatingStyle, starRating);
     }
 
     /**
@@ -221,11 +222,11 @@
      * @return null if the rating is out of range, a new Rating instance otherwise.
      */
     public static Rating newPercentageRating(float percent) {
-        if ((percent < 0.0f) || (percent > 100.0f)) {
+        if (percent >= 0.0f && percent <= 100.0f) {
+            return new Rating(RATING_PERCENTAGE, percent);
+        } else {
             Log.e(TAG, "Invalid percentage-based rating value");
             return null;
-        } else {
-            return new Rating(RATING_PERCENTAGE, percent);
         }
     }
 
diff --git a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
index fcb7d60..47debe9 100644
--- a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
+++ b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
@@ -23,5 +23,6 @@
  * @hide
  */
 interface IPlaybackMetricsManager {
-    void reportPlaybackMetrics(in PlaybackMetrics metrics, int userId);
+    void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId);
+    String getSessionId(int userId);
 }
\ No newline at end of file
diff --git a/media/java/android/media/metrics/PlaybackMetricsManager.java b/media/java/android/media/metrics/PlaybackMetricsManager.java
index 3606f53..d51ff47 100644
--- a/media/java/android/media/metrics/PlaybackMetricsManager.java
+++ b/media/java/android/media/metrics/PlaybackMetricsManager.java
@@ -16,6 +16,7 @@
 
 package android.media.metrics;
 
+import android.annotation.NonNull;
 import android.os.RemoteException;
 
 /**
@@ -38,10 +39,24 @@
 
     /**
      * Reports playback metrics.
+     * @hide
      */
-    public void reportPlaybackMetrics(PlaybackMetrics metrics) {
+    public void reportPlaybackMetrics(@NonNull String sessionId, PlaybackMetrics metrics) {
         try {
-            mService.reportPlaybackMetrics(metrics, mUserId);
+            mService.reportPlaybackMetrics(sessionId, metrics, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a playback session.
+     */
+    public PlaybackSession createSession() {
+        try {
+            String id = mService.getSessionId(mUserId);
+            PlaybackSession session = new PlaybackSession(id, this);
+            return session;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java
new file mode 100644
index 0000000..4ad8906
--- /dev/null
+++ b/media/java/android/media/metrics/PlaybackSession.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public final class PlaybackSession implements AutoCloseable {
+    private final @NonNull String mId;
+    private final @NonNull PlaybackMetricsManager mManager;
+    private boolean mClosed = false;
+
+    /**
+     * Creates a new PlaybackSession.
+     *
+     * @hide
+     */
+    public PlaybackSession(@NonNull String id, @NonNull PlaybackMetricsManager manager) {
+        mId = id;
+        mManager = manager;
+        AnnotationValidations.validate(NonNull.class, null, mId);
+        AnnotationValidations.validate(NonNull.class, null, mManager);
+    }
+
+    /**
+     * Reports playback metrics.
+     */
+    public void reportPlaybackMetrics(@NonNull PlaybackMetrics metrics) {
+        mManager.reportPlaybackMetrics(mId, metrics);
+    }
+
+    public @NonNull String getId() {
+        return mId;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PlaybackSession that = (PlaybackSession) o;
+        return Objects.equals(mId, that.mId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mId);
+    }
+
+    @Override
+    public void close() throws Exception {
+        mClosed = true;
+    }
+}
diff --git a/media/native/midi/MidiDeviceInfo.cpp b/media/native/midi/MidiDeviceInfo.cpp
index ac68d26..8a573fb 100644
--- a/media/native/midi/MidiDeviceInfo.cpp
+++ b/media/native/midi/MidiDeviceInfo.cpp
@@ -90,13 +90,13 @@
 
 status_t MidiDeviceInfo::readStringVector(
         const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength) {
-    std::unique_ptr<std::vector<std::unique_ptr<String16>>> v;
+    std::optional<std::vector<std::optional<String16>>> v;
     status_t result = parcel->readString16Vector(&v);
     if (result != OK) return result;
     vectorPtr->clear();
-    if (v.get() != nullptr) {
+    if (v) {
         for (const auto& iter : *v) {
-            if (iter.get() != nullptr) {
+            if (iter) {
                 vectorPtr->push_back(*iter);
             } else {
                 vectorPtr->push_back(String16());
diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h
index 42cad43..44fe56f 100644
--- a/native/webview/plat_support/draw_fn.h
+++ b/native/webview/plat_support/draw_fn.h
@@ -10,6 +10,7 @@
 #ifndef ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_FN_H_
 #define ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_FN_H_
 
+#include <android/surface_control.h>
 #include <vulkan/vulkan.h>
 
 #ifdef __cplusplus
@@ -21,7 +22,31 @@
 //
 // 1 is Android Q. This matches kAwDrawGLInfoVersion version 3.
 // 2 Adds transfer_function_* and color_space_toXYZD50 to AwDrawFn_DrawGLParams.
-static const int kAwDrawFnVersion = 2;
+// 3 Adds SurfaceControl related functions.
+static const int kAwDrawFnVersion = 3;
+
+// Returns parent ASurfaceControl for WebView overlays. It will be have same
+// geometry as the surface we draw into and positioned below it (underlay).
+// This does not pass ownership to webview, but guaranteed to be alive until
+// transaction from next removeOverlays call or functor destruction will be
+// finished.
+typedef ASurfaceControl* AwDrawFn_GetSurfaceControl();
+
+// Merges WebView transaction to be applied synchronously with current draw.
+// This doesn't pass ownership of the transaction, changes will be copied and
+// webview can free transaction right after the call.
+typedef void AwDrawFn_MergeTransaction(ASurfaceTransaction* transaction);
+
+enum AwDrawFnOverlaysMode {
+  // Indicated that webview should not promote anything to overlays this draw
+  // and remove all visible overlays.
+  // Added in version 3.
+  AW_DRAW_FN_OVERLAYS_MODE_DISABLED = 0,
+
+  // Indicates that webview can use overlays.
+  // Added in version 3.
+  AW_DRAW_FN_OVERLAYS_MODE_ENABLED = 1,
+};
 
 struct AwDrawFn_OnSyncParams {
   int version;
@@ -60,6 +85,19 @@
   float transfer_function_e;
   float transfer_function_f;
   float color_space_toXYZD50[9];
+
+  // Input: Indicates how webview should use overlays for this draw.
+  // Added in version 3.
+  AwDrawFnOverlaysMode overlays_mode;
+
+  // Input: WebView can call it to obtain parent surface control for overlays.
+  // Added in version 3.
+  AwDrawFn_GetSurfaceControl* get_surface_control;
+
+  // Input: WebView call this to apply ASurfaceTransaction synchronously with
+  // the draw.
+  // Added in version 3.
+  AwDrawFn_MergeTransaction* merge_transaction;
 };
 
 struct AwDrawFn_InitVkParams {
@@ -122,12 +160,33 @@
   int clip_top;
   int clip_right;
   int clip_bottom;
+
+  // Input: Indicates how webview should use overlays for this draw.
+  // Added in version 3.
+  AwDrawFnOverlaysMode overlays_mode;
+
+  // Input: WebView can call it to obtain parent surface control for overlays.
+  // Added in version 3.
+  AwDrawFn_GetSurfaceControl* get_surface_control;
+
+  // Input: WebView call this to apply ASurfaceTransaction synchronously with
+  // the draw.
+  // Added in version 3.
+  AwDrawFn_MergeTransaction* merge_transaction;
 };
 
 struct AwDrawFn_PostDrawVkParams {
   int version;
 };
 
+struct AwDrawFn_RemoveOverlaysParams {
+  int version;
+  // Input: WebView call this to apply ASurfaceTransaction synchronously with
+  // the draw.
+  // Added in version 3.
+  AwDrawFn_MergeTransaction* merge_transaction;
+};
+
 // Called on render thread while UI thread is blocked. Called for both GL and
 // VK.
 typedef void AwDrawFn_OnSync(int functor,
@@ -166,8 +225,15 @@
                                  void* data,
                                  AwDrawFn_PostDrawVkParams* params);
 
+// Can be called to make webview hide all overlays and stop updating them until
+// next draw. WebView must obtain new ASurfaceControl after this call to use as
+// parent for the overlays on next draw.
+typedef void AwDrawFn_RemoveOverlays(int functor,
+                                     void* data,
+                                     AwDrawFn_RemoveOverlaysParams* params);
+
 struct AwDrawFnFunctorCallbacks {
-  // No version here since this is passed from chromium to android.
+  // version is passed in CreateFunctor call.
   AwDrawFn_OnSync* on_sync;
   AwDrawFn_OnContextDestroyed* on_context_destroyed;
   AwDrawFn_OnDestroyed* on_destroyed;
@@ -175,6 +241,8 @@
   AwDrawFn_InitVk* init_vk;
   AwDrawFn_DrawVk* draw_vk;
   AwDrawFn_PostDrawVk* post_draw_vk;
+  // Added in version 3.
+  AwDrawFn_RemoveOverlays* remove_overlays;
 };
 
 enum AwDrawFnRenderMode {
@@ -185,10 +253,16 @@
 // Get the render mode. Result is static for the process.
 typedef AwDrawFnRenderMode AwDrawFn_QueryRenderMode(void);
 
-// Create a functor. |functor_callbacks| should be valid until OnDestroyed.
+// This available up to version 3, use the one below.
 typedef int AwDrawFn_CreateFunctor(void* data,
                                    AwDrawFnFunctorCallbacks* functor_callbacks);
 
+// Create a functor. |functor_callbacks| should be valid until OnDestroyed.
+typedef int AwDrawFn_CreateFunctor_v3(
+    void* data,
+    int version,
+    AwDrawFnFunctorCallbacks* functor_callbacks);
+
 // May be called on any thread to signal that the functor should be destroyed.
 // The functor will receive an onDestroyed when the last usage of it is
 // released, and it should be considered alive & active until that point.
@@ -197,8 +271,11 @@
 struct AwDrawFnFunctionTable {
   int version;
   AwDrawFn_QueryRenderMode* query_render_mode;
+  // Available up to version 3.
   AwDrawFn_CreateFunctor* create_functor;
   AwDrawFn_ReleaseFunctor* release_functor;
+  // Added in version 3.
+  AwDrawFn_CreateFunctor_v3* create_functor_v3;
 };
 
 #ifdef __cplusplus
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
index 7cce61b..ea57ea0 100644
--- a/native/webview/plat_support/draw_functor.cpp
+++ b/native/webview/plat_support/draw_functor.cpp
@@ -32,6 +32,15 @@
   AwDrawFnFunctorCallbacks callbacks;
 };
 
+AwDrawFnOverlaysMode GetOverlaysMode(uirenderer::OverlaysMode overlays_mode) {
+  switch (overlays_mode) {
+    case uirenderer::OverlaysMode::Disabled:
+      return AW_DRAW_FN_OVERLAYS_MODE_DISABLED;
+    case uirenderer::OverlaysMode::Enabled:
+      return AW_DRAW_FN_OVERLAYS_MODE_ENABLED;
+  }
+}
+
 void onSync(int functor, void* data,
             const uirenderer::WebViewSyncData& syncData) {
   AwDrawFn_OnSyncParams params = {
@@ -53,8 +62,20 @@
   delete support;
 }
 
+void removeOverlays(int functor, void* data,
+                    AwDrawFn_MergeTransaction merge_transaction) {
+  AwDrawFn_RemoveOverlaysParams params = {
+      .version = kAwDrawFnVersion,
+      .merge_transaction = merge_transaction
+  };
+  SupportData* support = static_cast<SupportData*>(data);
+  if (support->callbacks.remove_overlays)
+    support->callbacks.remove_overlays(functor, support->data, &params);
+}
+
 void draw_gl(int functor, void* data,
-             const uirenderer::DrawGlInfo& draw_gl_params) {
+             const uirenderer::DrawGlInfo& draw_gl_params,
+             const uirenderer::WebViewOverlayData& overlay_params) {
   float gabcdef[7];
   draw_gl_params.color_space_ptr->transferFn(gabcdef);
   AwDrawFn_DrawGLParams params = {
@@ -73,6 +94,9 @@
       .transfer_function_d = gabcdef[4],
       .transfer_function_e = gabcdef[5],
       .transfer_function_f = gabcdef[6],
+      .overlays_mode = GetOverlaysMode(overlay_params.overlaysMode),
+      .get_surface_control = overlay_params.getSurfaceControl,
+      .merge_transaction = overlay_params.mergeTransaction
   };
   COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_gl_params.transform),
                  mismatched_transform_matrix_sizes);
@@ -118,7 +142,9 @@
   support->callbacks.init_vk(functor, support->data, &params);
 }
 
-void drawVk(int functor, void* data, const uirenderer::VkFunctorDrawParams& draw_vk_params) {
+void drawVk(int functor, void* data,
+            const uirenderer::VkFunctorDrawParams& draw_vk_params,
+            const uirenderer::WebViewOverlayData& overlay_params) {
   SupportData* support = static_cast<SupportData*>(data);
   float gabcdef[7];
   draw_vk_params.color_space_ptr->transferFn(gabcdef);
@@ -142,6 +168,9 @@
       .clip_top = draw_vk_params.clip_top,
       .clip_right = draw_vk_params.clip_right,
       .clip_bottom = draw_vk_params.clip_bottom,
+      .overlays_mode = GetOverlaysMode(overlay_params.overlaysMode),
+      .get_surface_control = overlay_params.getSurfaceControl,
+      .merge_transaction = overlay_params.mergeTransaction
   };
   COMPILE_ASSERT(sizeof(params.color_space_toXYZD50) == sizeof(skcms_Matrix3x3),
                  gamut_transform_size_mismatch);
@@ -161,12 +190,14 @@
   support->callbacks.post_draw_vk(functor, support->data, &params);
 }
 
-int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
+int CreateFunctor_v3(void* data, int version,
+                     AwDrawFnFunctorCallbacks* functor_callbacks) {
   static bool callbacks_initialized = false;
   static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
       .onSync = &onSync,
       .onContextDestroyed = &onContextDestroyed,
       .onDestroyed = &onDestroyed,
+      .removeOverlays = &removeOverlays,
   };
   if (!callbacks_initialized) {
     switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
@@ -183,8 +214,23 @@
   }
   SupportData* support = new SupportData{
       .data = data,
-      .callbacks = *functor_callbacks,
   };
+
+  // These callbacks are available on all versions.
+  support->callbacks = {
+      .on_sync = functor_callbacks->on_sync,
+      .on_context_destroyed = functor_callbacks->on_context_destroyed,
+      .on_destroyed = functor_callbacks->on_destroyed,
+      .draw_gl = functor_callbacks->draw_gl,
+      .init_vk = functor_callbacks->init_vk,
+      .draw_vk = functor_callbacks->draw_vk,
+      .post_draw_vk = functor_callbacks->post_draw_vk,
+  };
+
+  if (version >= 3) {
+    support->callbacks.remove_overlays = functor_callbacks->remove_overlays;
+  }
+
   int functor = uirenderer::WebViewFunctor_create(
       support, webview_functor_callbacks,
       uirenderer::WebViewFunctor_queryPlatformRenderMode());
@@ -192,6 +238,12 @@
   return functor;
 }
 
+int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
+  const int kVersionForDeprecatedCreateFunctor = 2;
+  return CreateFunctor_v3(data, kVersionForDeprecatedCreateFunctor,
+                          functor_callbacks);
+}
+
 void ReleaseFunctor(int functor) {
   uirenderer::WebViewFunctor_release(functor);
 }
@@ -211,6 +263,7 @@
     .query_render_mode = &QueryRenderMode,
     .create_functor = &CreateFunctor,
     .release_functor = &ReleaseFunctor,
+    .create_functor_v3 = &CreateFunctor_v3,
   };
   return reinterpret_cast<intptr_t>(&function_table);
 }
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
index c7f5e9a..f11febc 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
@@ -20,6 +20,7 @@
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -85,8 +86,8 @@
                 case TelephonyManager.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED:
                     configs = b.getStringArray(CarrierConfigManager
                             .KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY);
-                    arg1 = intent.getStringExtra(TelephonyManager.EXTRA_APN_TYPE);
-                    arg2 = intent.getStringExtra(TelephonyManager.EXTRA_ERROR_CODE);
+                    arg1 = String.valueOf(intent.getIntExtra(TelephonyManager.EXTRA_APN_TYPE, -1));
+                    arg2 = intent.getStringExtra(TelephonyManager.EXTRA_DATA_FAIL_CAUSE);
                     break;
                 case TelephonyManager.ACTION_CARRIER_SIGNAL_RESET:
                     configs = b.getStringArray(CarrierConfigManager
@@ -141,10 +142,24 @@
             // case 1
             actionStr = splitStr[0];
         } else if (splitStr.length == 2 && arg1 != null && arg2 != null) {
-            // case 2
+            // case 2. The only thing that uses this is CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+            // and the carrier config for that can provide either an int or string for the apn type,
+            // depending on when it was introduced. Therefore, return a positive match if either
+            // the int version or the string version of the apn type in the broadcast matches.
+            String apnInIntFormat = arg1;
+            String apnInStringFormat = null;
+            try {
+                int apnInt = Integer.parseInt(apnInIntFormat);
+                apnInStringFormat = ApnSetting.getApnTypeString(apnInt);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "Got invalid apn type from broadcast: " + apnInIntFormat);
+            }
+
             String[] args = splitStr[0].split(INTRA_GROUP_DELIMITER);
-            if (args.length == 2 && TextUtils.equals(arg1, args[0]) &&
-                    TextUtils.equals(arg2, args[1])) {
+            boolean doesArg1Match = TextUtils.equals(apnInIntFormat, args[0])
+                    || (apnInStringFormat != null && TextUtils.equals(apnInStringFormat, args[0]));
+            if (args.length == 2 && doesArg1Match
+                    && TextUtils.equals(arg2, args[1])) {
                 actionStr = splitStr[1];
             }
         } else if ((splitStr.length == 2) && (arg1 != null) && (arg2 == null)) {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index a9c754d..c6c7142 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -410,7 +410,7 @@
                         InstallInstalling.this,
                         mInstallId,
                         broadcastIntent,
-                        PendingIntent.FLAG_UPDATE_CURRENT);
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
 
                 session.commit(pendingIntent.getIntentSender());
                 mCancelButton.setEnabled(false);
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
index caf9718..eea12ec 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
@@ -243,8 +243,8 @@
         }
 
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return PendingIntent.getActivity(mContext,
-                0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        return PendingIntent.getActivity(mContext, 0 /* request code */, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
     }
 
     /**
@@ -260,8 +260,8 @@
         }
 
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return PendingIntent.getActivity(mContext,
-                0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        return PendingIntent.getActivity(mContext, 0 /* request code */, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
     }
 
     /**
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
index c4dceb4..7bf27df 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
@@ -95,7 +95,8 @@
                 broadcastIntent.setPackage(getPackageName());
 
                 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, mUninstallId,
-                        broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                        broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT
+                                | PendingIntent.FLAG_MUTABLE);
 
                 int flags = allUsers ? PackageManager.DELETE_ALL_USERS : 0;
                 flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
index bf4b03c..7e0490a 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
@@ -269,7 +269,8 @@
         // Create a matching PendingIntent and use it to generate the IntentSender
         Intent broadcastIntent = new Intent(action);
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, packageName.hashCode(),
-                broadcastIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+                broadcastIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT
+                        | PendingIntent.FLAG_MUTABLE);
         return pendingIntent.getIntentSender();
     }
 
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 64dc2af..e6492aa 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -53,6 +53,7 @@
         "SettingsLibUtils",
         "SettingsLibEmergencyNumber",
         "SettingsLibTopIntroPreference",
+        "SettingsLibBannerMessagePreference",
     ],
 }
 
diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp
new file mode 100644
index 0000000..095975a
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/Android.bp
@@ -0,0 +1,13 @@
+android_library {
+    name: "SettingsLibBannerMessagePreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+          "androidx.preference_preference",
+    ],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/BannerMessagePreference/AndroidManifest.xml b/packages/SettingsLib/BannerMessagePreference/AndroidManifest.xml
new file mode 100644
index 0000000..56b886f
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21"/>
+
+</manifest>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/drawable/ic_warning.xml b/packages/SettingsLib/BannerMessagePreference/res/drawable/ic_warning.xml
new file mode 100644
index 0000000..c1f2c9f
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/drawable/ic_warning.xml
@@ -0,0 +1,26 @@
+<!--
+  Copyright (C) 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:pathData="M1,21L12,2L23,21H1ZM19.53,19L12,5.99L4.47,19H19.53ZM11,16V18H13V16H11ZM11,10H13V14H11V10Z"
+        android:fillColor="?android:attr/colorError"
+        android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml b/packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml
new file mode 100644
index 0000000..977e196
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="24dp"
+    android:paddingEnd="16dp"
+    android:paddingTop="24dp"
+    android:paddingBottom="8dp"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="@drawable/ic_warning"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="24dp"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@+id/banner_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/Banner.Text.Title"/>
+            <TextView
+                android:id="@+id/banner_summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/Banner.Text.Summary"/>
+        </LinearLayout>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="end">
+        <Button
+            android:id="@+id/banner_negative_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"/>
+
+        <Button
+            android:id="@+id/banner_positive_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
new file mode 100644
index 0000000..df47c64
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <style name="Banner.Text.Title"
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:textSize">16sp</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="Banner.Text.Summary"
+           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
new file mode 100644
index 0000000..5352552
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.StringRes;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * Banner message is a banner displaying important information (permission request, page error etc),
+ * and provide actions for user to address. It requires a user action to be dismissed.
+ */
+public class BannerMessagePreference extends Preference {
+
+    private static final String TAG = "BannerPreference";
+    private BannerMessagePreference.ButtonInfo mPositiveButtonInfo;
+    private BannerMessagePreference.ButtonInfo mNegativeButtonInfo;
+
+    public BannerMessagePreference(Context context) {
+        super(context);
+        init();
+    }
+
+    public BannerMessagePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        holder.setDividerAllowedAbove(true);
+        holder.setDividerAllowedBelow(true);
+
+        mPositiveButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_positive_btn);
+        mNegativeButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_negative_btn);
+
+        mPositiveButtonInfo.setUpButton();
+        mNegativeButtonInfo.setUpButton();
+
+        final TextView titleView = (TextView) holder.findViewById(R.id.banner_title);
+        final TextView summaryView = (TextView) holder.findViewById(R.id.banner_summary);
+
+        titleView.setText(getTitle());
+        summaryView.setText(getSummary());
+    }
+
+    private void init() {
+        mPositiveButtonInfo = new BannerMessagePreference.ButtonInfo();
+        mNegativeButtonInfo = new BannerMessagePreference.ButtonInfo();
+        setSelectable(false);
+        setLayoutResource(R.layout.banner_message);
+    }
+
+    /**
+     * Set the visibility state of positive button.
+     */
+    public BannerMessagePreference setPositiveButtonVisible(boolean isVisible) {
+        if (isVisible != mPositiveButtonInfo.mIsVisible) {
+            mPositiveButtonInfo.mIsVisible = isVisible;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
+     * Set the visibility state of negative button.
+     */
+    public BannerMessagePreference setNegativeButtonVisible(boolean isVisible) {
+        if (isVisible != mNegativeButtonInfo.mIsVisible) {
+            mNegativeButtonInfo.mIsVisible = isVisible;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
+     * Register a callback to be invoked when positive button is clicked.
+     */
+    public BannerMessagePreference setPositiveButtonOnClickListener(
+            View.OnClickListener listener) {
+        if (listener != mPositiveButtonInfo.mListener) {
+            mPositiveButtonInfo.mListener = listener;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
+     * Register a callback to be invoked when negative button is clicked.
+     */
+    public BannerMessagePreference setNegativeButtonOnClickListener(
+            View.OnClickListener listener) {
+        if (listener != mNegativeButtonInfo.mListener) {
+            mNegativeButtonInfo.mListener = listener;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
+     * Sets the text to be displayed in positive button.
+     */
+    public BannerMessagePreference setPositiveButtonText(@StringRes int textResId) {
+        final String newText = getContext().getString(textResId);
+        if (!TextUtils.equals(newText, mPositiveButtonInfo.mText)) {
+            mPositiveButtonInfo.mText = newText;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
+     * Sets the text to be displayed in negative button.
+     */
+    public BannerMessagePreference setNegativeButtonText(@StringRes int textResId) {
+        final String newText = getContext().getString(textResId);
+        if (!TextUtils.equals(newText, mNegativeButtonInfo.mText)) {
+            mNegativeButtonInfo.mText = newText;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    static class ButtonInfo {
+        private Button mButton;
+        private CharSequence mText;
+        private View.OnClickListener mListener;
+        private boolean mIsVisible = true;
+
+        void setUpButton() {
+            mButton.setText(mText);
+            mButton.setOnClickListener(mListener);
+
+            if (shouldBeVisible()) {
+                mButton.setVisibility(View.VISIBLE);
+            } else {
+                mButton.setVisibility(View.GONE);
+            }
+        }
+
+        /**
+         * By default, two buttons are visible.
+         * If user didn't set a text for a button, then it should not be shown.
+         */
+        private boolean shouldBeVisible() {
+            return mIsVisible && (!TextUtils.isEmpty(mText));
+        }
+    }
+}
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
index e7c0d96..4505dad 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
@@ -52,6 +52,9 @@
     public static String getAppContentDescription(Context context, String packageName,
             int userId) {
         final CharSequence appLabel = getApplicationLabel(context.getPackageManager(), packageName);
+        if (appLabel == null) {
+            return "";
+        }
         return context.getSystemService(UserManager.class).isManagedProfile(userId)
                 ? context.getString(R.string.accessibility_work_profile_app_description, appLabel)
                 : appLabel.toString();
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 2b30e0a..41af185 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> oor tot battery gelaai is"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot battery gelaai is"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Battery word tydelik beperk"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laai"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laai tans vinnig"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 0bebfab..8e4e402 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ኃይል እስከሚሞላ ድረስ ይቀራል"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ኃይል እስከሚሞላ ድረስ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ባትሪ ለጊዜው ተገድቧል"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 6eaf3a9..691ec046 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> إلى أن يتم شحن الجهاز بالكامل"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> إلى أن يتم شحن الجهاز بالكامل"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - تأثير محدود على البطارية مؤقتًا"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e207e1c..61214e0 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"চাৰ্জ হ’বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> চাৰ্জ হ\'বলৈ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - বেটাৰী সাময়িকভাৱে সীমিত কৰা হৈছে"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index ff1209c..db61527 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Enerjinin dolmasına <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - Enerjinin dolmasına <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareya müvəqqəti məhdudlaşdırılıb"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Naməlum"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Enerji doldurma"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Sürətlə doldurulur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index eb099c1..70fb363 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Napuniće se za <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napuniće se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – baterija je trenutno ograničena"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index e6e49ab..8a0db82 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Засталося <xliff:g id="TIME">%1$s</xliff:g> да поўнай зарадкі"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўнай зарадкі"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарад акумулятара часова абмежаваны"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 251c4dd..27dcf10 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Батерията е временно ограничена"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 6a99a84..29862e6 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -211,9 +211,9 @@
     <string name="adb_wireless_error" msgid="721958772149779856">"সমস্যা"</string>
     <string name="adb_wireless_settings" msgid="2295017847215680229">"ওয়্যারলেস ডিবাগিং"</string>
     <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"কোন কোন ডিভাইস উপলভ্য আছে তা দেখে নিয়ে ব্যবহার করার জন্য, ওয়্যারলেস ডিবাগিং চালু করুন"</string>
-    <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR কোড ব্যবহার করে ডিভাইস যোগ করুন"</string>
+    <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR কোড ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
     <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR কোড স্ক্যানার ব্যবহার করে নতুন ডিভাইস যোগ করুন"</string>
-    <string name="adb_pair_method_code_title" msgid="1122590300445142904">"যোগ করার কোড ব্যবহার করে ডিভাইস যোগ করুন"</string>
+    <string name="adb_pair_method_code_title" msgid="1122590300445142904">"পেয়ারিং কোড ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
     <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ছয় সংখ্যার কোড ব্যবহার করে নতুন ডিভাইস যোগ করুন"</string>
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"যোগ করা ডিভাইস"</string>
     <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"এখন কানেক্ট রয়েছে"</string>
@@ -222,16 +222,16 @@
     <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"ডিভাইসে আঙ্গুলের ছাপ: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
     <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"কানেক্ট করা যায়নি"</string>
     <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>টি সঠিক নেটওয়ার্কে কানেক্ট আছে কিনা দেখে নিন"</string>
-    <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"ডিভাইসের সাথে যোগ করুন"</string>
-    <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"ওয়াই-ফাই যোগ করার কোড"</string>
-    <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"যোগ করা যায়নি"</string>
+    <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"ডিভাইসের সাথে পেয়ার করুন"</string>
+    <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"ওয়াই-ফাইয়ের সাথে পেয়ার করার কোড"</string>
+    <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"পেয়ার করা যায়নি"</string>
     <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"ডিভাইসটি একই নেটওয়ার্কে কানেক্ট আছে কিনা দেখে নিন।"</string>
-    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইস যোগ করুন"</string>
+    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"ডিভাইস যোগ করা হচ্ছে…"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ডিভাইস যোগ করা যায়নি। এটি দুটি কারণে হয়ে থাকে - QR কোডটি সঠিক নয় বা ডিভাইসটি একই নেটওয়ার্কে কানেক্ট করা নেই।"</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP অ্যাড্রেস ও পোর্ট"</string>
     <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR কোড স্ক্যান করুন"</string>
-    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR কোড স্ক্যান করে ওয়াই-ফাইয়ের সাহায্যে ডিভাইস যোগ করুন"</string>
+    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
     <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"একটি ওয়াই-ফাই নেটওয়ার্কের সাথে কানেক্ট করুন"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"ত্রুটি প্রতিবেদনের শর্টকাট"</string>
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"সম্পূর্ণ চার্জ হতে <xliff:g id="TIME">%1$s</xliff:g> বাকি আছে"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>-এ সম্পূর্ণ চার্জ হয়ে যাবে"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ব্যাটারি কিছুক্ষণের জন্য সীমিত করা হয়েছে"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"অজানা"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"চার্জ হচ্ছে"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্রুত চার্জ হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index aeb7f2e..4704ec8 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Napunit će se za <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napunit će se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Baterija je privremeno ograničena"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index df4c99e..5d04963 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -66,7 +66,7 @@
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Desconnectat"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"S\'està desconnectant..."</string>
     <string name="bluetooth_connecting" msgid="5871702668260192755">"S\'està connectant…"</string>
-    <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connectat"</string>
+    <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> Connectat"</string>
     <string name="bluetooth_pairing" msgid="4269046942588193600">"S\'està vinculant..."</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connectat (sense accés al telèfon)"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connectat (sense contingut multimèdia)"</string>
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>: bateria limitada temporalment"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index e563ca5..a99a4da 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Do nabití zbývá: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do nabití"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Baterie dočasně omezena"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznámé"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíjí se"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rychlé nabíjení"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 8a3d054..c90155e 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Opladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – opladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batteriet er midlertidigt begrænset"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ukendt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Oplader"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Oplader hurtigt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 624b299..b5b9fc4 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Inaktiv. Zum Wechseln tippen."</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiv. Zum Wechseln tippen."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"Standby-Status der App:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"Einstellungen für Medientranscodierung"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"Transcodierung deaktivieren"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"Transcodierung für Apps aktivieren"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive Dienste"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Noch <xliff:g id="TIME">%1$s</xliff:g> bis zur Aufladung"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> bis zur Aufladung"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Akku vorübergehend eingeschränkt"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 7ea9050..203ec40 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> για ολοκλήρωση της φόρτισης"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για την ολοκλήρωση της φόρτισης"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Η μπαταρία περιορίστηκε προσωρινά."</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 7affb5c..08ff550 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -196,7 +196,7 @@
     <string name="choose_profile" msgid="343803890897657450">"Elegir perfil"</string>
     <string name="category_personal" msgid="6236798763159385225">"Personal"</string>
     <string name="category_work" msgid="4014193632325996115">"Trabajo"</string>
-    <string name="development_settings_title" msgid="140296922921597393">"Opciones para programadores"</string>
+    <string name="development_settings_title" msgid="140296922921597393">"Opciones para desarrolladores"</string>
     <string name="development_settings_enable" msgid="4285094651288242183">"Activar opciones para programador"</string>
     <string name="development_settings_summary" msgid="8718917813868735095">"Establecer opciones para desarrollar aplicaciones"</string>
     <string name="development_settings_not_available" msgid="355070198089140951">"Las opciones de programador no están disponibles para este usuario."</string>
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> para completar la carga"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batería limitada temporalmente"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápido"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index ccdc1c4..6f6a1a1 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> hasta cargarse completamente"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> hasta cargarse completamente)"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>: batería limitada temporalmente"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 852d6df..9d6326e 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Täislaadimiseni on jäänud <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – akutase on ajutiselt piiratud"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 6b6b9b6..01afa17 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>: bateria mugatuta egongo da aldi batez"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index af1e55b..dd7ab96 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> مانده تا شارژ کامل"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - باتری موقتاً محدود شده است"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ناشناس"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"در حال شارژ شدن"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"درحال شارژ شدن سریع"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 8e819ef..b86b02d 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> jäljellä täyteen lataukseen"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täyteen lataukseen"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Akun käyttöä rajoitettu tilapäisesti"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 4754d15..0bca1db 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la charge complète"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> : <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Pile limitée temporairement"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index a3863f59..ebde43b 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à ce que la batterie soit chargée"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batterie limitée temporairement"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 81e79e4..b040817 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> para completar a carga"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> (batería limitada temporalmente)"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 9bf0970..c1bd7ca 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"નિષ્ક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"સક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ઍપ સ્ટૅન્ડબાયની સ્થિતિ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"મીડિયાનું ફૉર્મેટ બદલવાની પ્રક્રિયાના સેટિંગ"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ફૉર્મેટ બદલવાની પ્રક્રિયા બંધ કરો"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"ઍપ માટે ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ચાલુ સેવાઓ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ચાર્જ થવામાં <xliff:g id="TIME">%1$s</xliff:g> બાકી છે"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જ થવા માટે <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - બૅટરીનો વપરાશ હંગામી રૂપે મર્યાદિત છે"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 151b861..d9153a1 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"चार्ज पूरा होने में <xliff:g id="TIME">%1$s</xliff:g> बचा है"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - कुछ समय के लिए, बैटरी का सीमित इस्तेमाल होगा"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index d37879f..b51e096 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Napunit će se za <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napunit će se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Baterija je privremeno ograničena"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 4ac5308..33770fc 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> van hátra a feltöltésből"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a feltöltésig"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Akkumulátor ideiglenesen korlátozva"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Gyorstöltés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b0734fd..06d70f8 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> մինչև լիցքավորումը"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լիցքավորումը"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Մարտկոցը ժամանակավորապես սահմանափակված է"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 9db21c7..4123d9e 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Sisa <xliff:g id="TIME">%1$s</xliff:g> hingga terisi penuh"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi terisi penuh"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Daya baterai terbatas untuk sementara"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index d9ee03a..3b9bef8 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> að fullri hleðslu"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> að fullri hleðslu"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Rafhlaða takmörkuð tímabundið"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 57378e7..1ab6b24 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -66,7 +66,7 @@
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnesso"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnessione…"</string>
     <string name="bluetooth_connecting" msgid="5871702668260192755">"Connessione…"</string>
-    <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso"</string>
+    <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> Connesso"</string>
     <string name="bluetooth_pairing" msgid="4269046942588193600">"Accoppiamento…"</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (telefono escluso)"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (contenuti multimediali esclusi)"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fd53f14..15868d5 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"אפליקציה לא פעילה. הקש כדי להחליף מצב."</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"אפליקציה פעילה. הקש כדי להחליף מצב."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"אפליקציה במצב המתנה:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"הגדרות של המרת קידוד למדיה"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"השבתה של המרת קידוד"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"הפעלה של המרת קידוד לאפליקציות"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"שירותים פועלים"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"הצגת השירותים הפועלים כעת ושליטה בהם"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏יישום WebView"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>‏ - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"נשארו <xliff:g id="TIME">%1$s</xliff:g> עד הטעינה"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> עד הטעינה"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - הסוללה מוגבלת באופן זמני"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"לא ידוע"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"בטעינה"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"הסוללה נטענת מהר"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index c0aa74b..89ee98e 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"充電完了まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電完了まで <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 電池の使用が一時的に制限されています"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 09f3ff5..2bc1c4d 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Зарядталғанға дейін <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарея жұмысы уақытша шектелген"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядталуда"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 42e6a53..7306cf8 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបសាកថ្មពេញ"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើប​សាកថ្មពេញ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - បានដាក់កម្រិតថ្ម​ជាបណ្ដោះអាសន្ន"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"មិន​ស្គាល់"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងបញ្ចូល​ថ្ម"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 658b987..0c1502c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಇದೆ"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯ ಬೇಕು"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಬ್ಯಾಟರಿ ತಾತ್ಕಾಲಿಕವಾಗಿ ಸೀಮಿತವಾಗಿದೆ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 2b0843d..1322344 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"충전 완료까지 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 완료까지 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 일시적으로 배터리 사용 제한"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 499fd88..9697aa7 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> кийин толук кубатталып бүтөт"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> кийин толук кубатталып бүтөт"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батареяны колдонуу убактлуу чектелген"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Белгисиз"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Кубатталууда"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ыкчам кубатталууда"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index a5be601..7201222 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -399,9 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"ບໍ່ໄດ້ນຳໃຊ້. ແຕະບໍ່ສັບປ່ຽນ."</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"ນຳໃຊ້ຢູ່. ແຕະເພື່ອສັບປ່ຽນ."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ສະຖານະສະແຕນບາຍແອັບ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <string name="transcode_settings_title" msgid="2581975870429850549">"ການຕັ້ງຄ່າການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດມີເດຍ"</string>
-    <string name="transcode_enable_all" msgid="9102460144086871903">"ປິດການນຳໃຊ້ການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດ"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ເປີດການນຳໃຊ້ການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດສຳລັບແອັບ"</string>
+    <string name="transcode_settings_title" msgid="2581975870429850549">"ການຕັ້ງຄ່າການປ່ຽນຮູບແບບລະຫັດມີເດຍ"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ປິດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດ"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"ເປີດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດສຳລັບແອັບ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ຈຳກັດແບັດເຕີຣີຊົ່ວຄາວ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ກຳລັງສາກໄຟ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ກຳລັງສາກໄຟດ່ວນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 181fb10..e62eeb2 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Iki visiškos įkrovos liko <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – iki visiškos įkrovos liko <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – akumuliatorius laikinai apribotas"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nežinomas"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Kraunasi..."</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Greitai įkraunama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 717e2b0..2f30561 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Vēl <xliff:g id="TIME">%1$s</xliff:g> līdz pilnai uzlādei"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>, akumulatora uzlāde pagaidām ierobežota"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nezināms"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Uzlāde"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Notiek ātrā uzlāde"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 2ccb150..1936fe2 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Уште <xliff:g id="TIME">%1$s</xliff:g> до целосно полнење"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> до целосно полнење"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батеријата е привремено ограничена"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Се полни"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо полнење"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 768ad5e..de4a49a 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"നിഷ്‌ക്രിയം. മാറ്റുന്നതിനു ടാപ്പുചെയ്യുക."</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ആപ്പ് സ്‌റ്റാൻഡ്‌ബൈ നില:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"മീഡിയ ട്രാൻസ്കോഡ് ചെയ്യൽ ക്രമീകരണം"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ട്രാൻസ്കോഡ് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"ആപ്പുകൾക്കായി ട്രാൻസ്കോഡ് ചെയ്യുന്നത് പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"പൂർണ്ണമായി ചാർജാവാൻ <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമായി ചാർജാവാൻ <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ബാറ്ററി താൽക്കാലം പരിമിതപ്പെടുത്തി"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"അജ്ഞാതം"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ചാർജ് ചെയ്യുന്നു"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"അതിവേഗ ചാർജിംഗ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 61ebca5..dee8add 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Цэнэглэх хүртэл үлдсэн <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - цэнэглэх хүртэл <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейг түр хугацаанд хязгаарласан"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index ef319c3..60ad68e 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"निष्क्रिय. टॉगल करण्यासाठी टॅप करा."</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"अ‍ॅप स्टँडबाय स्थिती: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"मीडिया ट्रान्सकोडिंगची सेटिंग्ज"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ट्रान्सकोडिंग बंद करा"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"ॲप्ससाठी ट्रान्सकोडिंग सुरू करा"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> पर्यंत पूर्ण चार्ज होईल"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पर्यंत पूर्ण चार्ज होईल"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - बॅटरी तात्पुरती मर्यादित आहे"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 83c0384..e4d5912 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> lagi sehingga dicas penuh"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga dicas"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Bateri terhad untuk sementara"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index f398487..09a8bf8 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"အားပြည့်ရန် <xliff:g id="TIME">%1$s</xliff:g> ကျန်သည်"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားပြည့်ရန် <xliff:g id="TIME">%2$s</xliff:g> ကျန်သည်"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ဘက်ထရီ ယာယီကန့်သတ်ထားသည်"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"မသိ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"အားသွင်းနေပါသည်"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"အမြန် အားသွင်းနေသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 0ef5809..d1af289 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> til batteriet er fulladet"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til batteriet er fulladet"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batteriet er midlertidig begrenset"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index b956e21..0c6114b 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"निष्क्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"एपको स्ट्यान्डबाई अवस्था:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"मिडिया ट्रान्सकोडिङ सेटिङ"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ट्रान्सकोडिङ अफ गर्नुहोस्"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"एपहरूमा ट्रान्सकोडिङ अन गर्नुहोस्"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"पूर्ण चार्ज हुन <xliff:g id="TIME">%1$s</xliff:g> बाँकी"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"पूर्ण चार्ज हुन <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> लाग्छ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - केही समयका लागि ब्याट्री प्रयोग सीमित गरिएको छ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 3223857..a409756 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Nog <xliff:g id="TIME">%1$s</xliff:g> tot opgeladen"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot opgeladen"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batterij tijdelijk beperkt"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Opladen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Snel opladen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 11bb550..0a0eeff 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"ନିଷ୍କ୍ରିୟ। ଟୋଗଲ୍‌ କରିବାକୁ ଟାପ୍‌ କରନ୍ତୁ।"</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"ସକ୍ରିୟ। ବଦଳାଇବା ପାଇଁ ଟାପ୍‌ କରନ୍ତୁ"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ଆପ୍ ଷ୍ଟାଣ୍ଡବାଏ ଅବସ୍ଥା:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"ମିଡିଆ ଟ୍ରାନ୍ସକୋଡିଂ ସେଟିଂସ୍"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ଟ୍ରାନ୍ସକୋଡିଂ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"ଆପଗୁଡ଼ିକ ପାଇଁ ଟ୍ରାନ୍ସକୋଡିଂ ସକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍‌ଭ୍ୟୁ ପ୍ରୟୋଗ"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ଚାର୍ଜ ହେବା ପାଇଁ <xliff:g id="TIME">%1$s</xliff:g> ବାକି ଅଛି"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ଚାର୍ଜ ହେବା ପର୍ଯ୍ୟନ୍ତ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ବ୍ୟାଟେରୀ ଅସ୍ଥାୟୀ ଭାବେ ସୀମିତ ଅଛି"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ଅଜ୍ଞାତ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ଚାର୍ଜ ହେଉଛି"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 8d66f3c..c9c37d9 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"ਅਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"ਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ਐਪ ਸਟੈਂਡਬਾਈ ਸਥਿਤੀ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"ਮੀਡੀਆ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੈਟਿੰਗਾਂ"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਬੰਦ ਕਰੋ"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"ਐਪਾਂ ਲਈ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਤੱਕ ਚਾਰਜ ਹੋ ਜਾਵੇਗੀ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਕੁਝ ਸਮੇਂ ਲਈ ਸੀਮਤ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index ed96c46..e894c2c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Do naładowania <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – do naładowania <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – bateria tymczasowo ograniczona"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 46d6d0a..57a0454 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Au mai rămas <xliff:g id="TIME">%1$s</xliff:g> până la încărcare"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> până la încărcare"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – baterie limitată temporar"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 2a79ad3..09b8de0 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> до полной зарядки"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> • Уровень заряда временно ограничен"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Идет зарядка"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Быстрая зарядка"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 78f3558..d36140f 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ආරෝපණය වන තෙක් <xliff:g id="TIME">%1$s</xliff:g> ඇත"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය වන තෙක් <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - බැටරිය තාවකාලිකව සීමිතයි"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 152c7a8..096e95e 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Zostávajúci čas do úplného nabitia: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batéria je dočasne obmedzená"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznáme"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíja sa"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rýchle nabíjanie"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index a2f093e..345fa36 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Še <xliff:g id="TIME">%1$s</xliff:g> do polne napolnjenosti"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do polne napolnjenosti"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – baterija je začasno omejena"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b458917..3953a6a4f 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura deri në karikim"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të karikohet"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Bateria e kufizuar përkohësisht"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Po ngarkon me shpejtësi"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 970c70f..70b2879 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Напуниће се за <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – напуниће се за <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – батерија је тренутно ограничена"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 42d9077..f466e88 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> kvar till full laddning"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till full laddning"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – batteriet är tillfälligt begränsat"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index f1a4199..e1060fec 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Imebakisha <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ijae chaji"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Betri imedhibitiwa kwa muda"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 2d696c5..ba98d79 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"முழு சார்ஜாக <xliff:g id="TIME">%1$s</xliff:g> ஆகும்"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - முழு சார்ஜாக <xliff:g id="TIME">%2$s</xliff:g> ஆகும்"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>-பேட்டரி தற்காலிகக் கட்டுப்பாட்டிலுள்ளது"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"அறியப்படாத"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"சார்ஜ் ஆகிறது"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"வேகமாக சார்ஜாகிறது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 8e0f0b6..0b93979 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ఛార్జ్ అవ్వడానికి <xliff:g id="TIME">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జ్ అవ్వడానికి <xliff:g id="TIME">%2$s</xliff:g> పడుతుంది"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> -బ్యాటరీ తాత్కాలికంగా పరిమితం చేయబడింది"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 81895b9..a31e146 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"เหลือ <xliff:g id="TIME">%1$s</xliff:g> จนกว่าจะชาร์จเต็ม"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะชาร์จ"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - การชาร์จแบตเตอรี่จำกัดชั่วคราว"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 5d1630f..bbb7779 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ang natitira bago matapos mag-charge"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hanggang matapos mag-charge"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pansamantalang limitado ang baterya"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Hindi Kilala"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nagcha-charge"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mabilis na charge"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 34c96a8..fba7f41 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Şarj olmaya <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - şarj olmaya <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pil geçici olarak sınırlı"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index de2456c..b633752 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> до повного заряду"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – дані акумулятора тимчасово недоступні"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7842ba9..b4d8ad2 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -399,12 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"غیر فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ایپ اسٹینڈ بائی کی حالت:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <!-- no translation found for transcode_settings_title (2581975870429850549) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (9102460144086871903) -->
-    <skip />
-    <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
-    <skip />
+    <string name="transcode_settings_title" msgid="2581975870429850549">"میڈیا ٹرانسکوڈنگ کی ترتیبات"</string>
+    <string name="transcode_enable_all" msgid="9102460144086871903">"ٹرانسکوڈنگ غیر فعال کریں"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"ایپس کے لئے ٹرانسکوڈنگ فعال کریں"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"چل رہی سروسز"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏WebView کا نفاذ"</string>
@@ -452,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>‎"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"چارج ہونے میں <xliff:g id="TIME">%1$s</xliff:g> باقی"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> چارج ہونے تک"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - بیٹری عارضی طور پر محدود ہے"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 9457d90..5bb422e 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ichida toʻladi"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> ichida toʻladi"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Quvvat darajasi vaqtincha cheklangan"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 235987c..0acf941 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Còn <xliff:g id="TIME">%1$s</xliff:g> nữa là sạc đầy"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> nữa là sạc đầy"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Thời lượng pin bị hạn chế tạm thời"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Không xác định"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Đang sạc"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Đang sạc nhanh"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 46188e9..ca2ad87 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"还剩 <xliff:g id="TIME">%1$s</xliff:g>充满电"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>后充满电"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 暂时限用电池"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"正在充电"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充电"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 6f5c025..16ca19d 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -399,9 +399,9 @@
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"未啟用。輕按即可切換。"</string>
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"已啟用。輕按即可切換。"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"備用應用程式狀態:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
-    <string name="transcode_settings_title" msgid="2581975870429850549">"媒體轉碼功能設定"</string>
+    <string name="transcode_settings_title" msgid="2581975870429850549">"媒體轉碼設定"</string>
     <string name="transcode_enable_all" msgid="9102460144086871903">"停用轉碼功能"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"替應用程式啟用轉碼功能"</string>
+    <string name="transcode_skip_apps" msgid="8249721984597390142">"為應用程式啟用轉碼功能"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"執行中的服務"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並控制目前正在執行中的服務"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string>
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"還需 <xliff:g id="TIME">%1$s</xliff:g>才能充滿電"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 還需 <xliff:g id="TIME">%2$s</xliff:g>才能充滿電"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 暫時限制電池充電"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充電"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index f966df6..810119b 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g>後充飽電"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽電"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 暫時限制電池用量"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 8ad37d3..23beeb1 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -449,8 +449,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> esele ize ishaje"</string>
     <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ize igcwale"</string>
-    <!-- no translation found for power_charging_limited (5902301801611726210) -->
-    <skip />
+    <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ibhethri ikhawulelwe okwesikhashana"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Akwaziwa"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Iyashaja"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ishaja ngokushesha"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 9f16d03..ac20ee1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -408,7 +408,8 @@
     }
 
     /**
-     * Checks if an admin has enforced minimum password quality requirements on the given user.
+     * Checks if an admin has enforced minimum password quality or complexity requirements on the
+     * given user.
      *
      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
      * or {@code null} if no quality requirements are set. If the requirements are set by
@@ -428,6 +429,30 @@
         }
 
         LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+        final int aggregatedComplexity = dpm.getAggregatedPasswordComplexityForUser(userId);
+        if (aggregatedComplexity > DevicePolicyManager.PASSWORD_COMPLEXITY_NONE) {
+            // First, check if there's a Device Owner. If so, then only it can apply password
+            // complexity requiremnts (there can be no secondary profiles).
+            final UserHandle deviceOwnerUser = dpm.getDeviceOwnerUser();
+            if (deviceOwnerUser != null) {
+                return new EnforcedAdmin(dpm.getDeviceOwnerComponentOnAnyUser(), deviceOwnerUser);
+            }
+
+            // The complexity could be enforced by a Profile Owner - either in the current user
+            // or the current user is the parent user that is affected by the profile owner.
+            for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) {
+                final ComponentName profileOwnerComponent = dpm.getProfileOwnerAsUser(userInfo.id);
+                if (profileOwnerComponent != null) {
+                    return new EnforcedAdmin(profileOwnerComponent, getUserHandleOf(userInfo.id));
+                }
+            }
+
+            // Should not get here: A Device Owner or Profile Owner should be found.
+            throw new IllegalStateException(
+                    String.format("Could not find admin enforcing complexity %d for user %d",
+                            aggregatedComplexity, userId));
+        }
+
         if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) {
             // userId is managed profile and has a separate challenge, only consider
             // the admins in that user.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 59d8acb..8fd1910 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -49,6 +49,7 @@
  */
 public class BluetoothEventManager {
     private static final String TAG = "BluetoothEventManager";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final LocalBluetoothAdapter mLocalAdapter;
     private final CachedBluetoothDeviceManager mDeviceManager;
@@ -366,6 +367,9 @@
          *               BluetoothDevice.UNBOND_REASON_*
          */
         private void showUnbondMessage(Context context, String name, int reason) {
+            if (DEBUG) {
+                Log.d(TAG, "showUnbondMessage() name : " + name + ", reason : " + reason);
+            }
             int errorMsg;
 
             switch (reason) {
@@ -382,6 +386,7 @@
                 case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
                 case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
                 case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
+                case BluetoothDevice.UNBOND_REASON_REMOVED:
                     errorMsg = R.string.bluetooth_pairing_error_message;
                     break;
                 default:
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index ba1dc64..6a4d650 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -35,6 +35,8 @@
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 
+import com.android.settingslib.R;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,6 +51,8 @@
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothEventManagerTest {
 
+    private static final String DEVICE_NAME = "test_device_name";
+
     @Mock
     private LocalBluetoothAdapter mLocalAdapter;
     @Mock
@@ -71,6 +75,8 @@
     private BluetoothDevice mDevice2;
     @Mock
     private LocalBluetoothProfileManager mLocalProfileManager;
+    @Mock
+    private BluetoothUtils.ErrorListener mErrorListener;
 
     private Context mContext;
     private Intent mIntent;
@@ -92,6 +98,7 @@
 
         mCachedDevice1 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1);
         mCachedDevice2 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2);
+        BluetoothUtils.setErrorListener(mErrorListener);
     }
 
     @Test
@@ -344,4 +351,80 @@
         assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
         assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
     }
+
+    @Test
+    public void showUnbondMessage_reasonRemoved_showCorrectedErrorCode() {
+        mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+        mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+        mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_REMOVED);
+        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+        when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+                eq(R.string.bluetooth_pairing_error_message));
+    }
+
+    @Test
+    public void showUnbondMessage_reasonAuthTimeout_showCorrectedErrorCode() {
+        mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+        mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+        mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT);
+        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+        when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+                eq(R.string.bluetooth_pairing_error_message));
+    }
+
+    @Test
+    public void showUnbondMessage_reasonRemoteDeviceDown_showCorrectedErrorCode() {
+        mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+        mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+        mIntent.putExtra(BluetoothDevice.EXTRA_REASON,
+                BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN);
+        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+        when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+                eq(R.string.bluetooth_pairing_device_down_error_message));
+    }
+
+    @Test
+    public void showUnbondMessage_reasonAuthRejected_showCorrectedErrorCode() {
+        mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+        mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+        mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_REJECTED);
+        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+        when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+                eq(R.string.bluetooth_pairing_rejected_error_message));
+    }
+
+    @Test
+    public void showUnbondMessage_reasonAuthFailed_showCorrectedErrorCode() {
+        mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+        mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+        mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_FAILED);
+        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+        when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+                eq(R.string.bluetooth_pairing_pin_error_message));
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
new file mode 100644
index 0000000..8ab0298
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.preference.PreferenceViewHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BannerMessagePreferenceTest {
+
+    private Context mContext;
+    private View mRootView;
+    private BannerMessagePreference mBannerPreference;
+    private PreferenceViewHolder mHolder;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mRootView = View.inflate(mContext, R.layout.banner_message, null /* parent */);
+        mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
+        mBannerPreference = new BannerMessagePreference(mContext);
+    }
+
+    @Test
+    public void onBindViewHolder_shouldSetTitle() {
+        mBannerPreference.setTitle("test");
+
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((TextView) mRootView.findViewById(R.id.banner_title)).getText())
+                .isEqualTo("test");
+    }
+
+    @Test
+    public void onBindViewHolder_shouldSetSummary() {
+        mBannerPreference.setSummary("test");
+
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((TextView) mRootView.findViewById(R.id.banner_summary)).getText())
+                .isEqualTo("test");
+    }
+
+    @Test
+    public void setPositiveButtonText_shouldShowPositiveButton() {
+        mBannerPreference.setPositiveButtonText(R.string.tts_settings_title);
+
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_positive_btn)).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setNegativeButtonText_shouldShowNegativeButton() {
+        mBannerPreference.setNegativeButtonText(R.string.tts_settings_title);
+
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_negative_btn)).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void withoutSetPositiveButtonText_shouldHidePositiveButton() {
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_positive_btn)).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void withoutSetNegativeButtonText_shouldHideNegativeButton() {
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_negative_btn)).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setPositiveButtonVisible_withTrue_shouldShowPositiveButton() {
+        mBannerPreference.setPositiveButtonText(R.string.tts_settings_title);
+
+        mBannerPreference.setPositiveButtonVisible(true);
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_positive_btn)).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setPositiveButtonVisible_withFalse_shouldHidePositiveButton() {
+        mBannerPreference.setPositiveButtonText(R.string.tts_settings_title);
+
+        mBannerPreference.setPositiveButtonVisible(false);
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_positive_btn)).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setNegativeButtonVisible_withTrue_shouldShowNegativeButton() {
+        mBannerPreference.setNegativeButtonText(R.string.tts_settings_title);
+
+        mBannerPreference.setNegativeButtonVisible(true);
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_negative_btn)).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setNegativeButtonVisible_withFalse_shouldHideNegativeButton() {
+        mBannerPreference.setNegativeButtonText(R.string.tts_settings_title);
+
+        mBannerPreference.setNegativeButtonVisible(false);
+        mBannerPreference.onBindViewHolder(mHolder);
+
+        assertThat(((Button) mRootView.findViewById(R.id.banner_negative_btn)).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
index 5e5a9d9..c33f02df 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
@@ -82,6 +82,7 @@
     private static PendingIntent getPendingActivity(Context context) {
         Intent intent = new Intent("com.android.settings.WIFI_TETHER_SETTINGS")
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        return PendingIntent.getActivity(context, 0, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
     }
 }
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index af12ddd..48c0dc4 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -319,7 +319,6 @@
                     Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
                     Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
                     Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
-                    Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
                     Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
                     Settings.Global.LOCK_SOUND,
                     Settings.Global.LOOPER_STATS,
@@ -576,8 +575,6 @@
                     Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
                     Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
                     Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
-                    Settings.Global.ISOLATED_STORAGE_LOCAL,
-                    Settings.Global.ISOLATED_STORAGE_REMOTE,
                     Settings.Global.APPOP_HISTORY_PARAMETERS,
                     Settings.Global.APPOP_HISTORY_MODE,
                     Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a97af4b..2e3ea24 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -70,6 +70,7 @@
     <uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
     <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
     <uses-permission android:name="android.permission.DUMP" />
+    <uses-permission android:name="android.permission.CONTROL_UI_TRACING" />
     <uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
     <!-- Internal permissions granted to the shell. -->
@@ -146,6 +147,7 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
     <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
     <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+    <uses-permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" />
     <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 014d73f..2ea0c22 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -33,6 +33,13 @@
     srcs: ["src/com/android/systemui/EventLogTags.logtags"],
 }
 
+java_library {
+    name: "SystemUI-sensors",
+    srcs: [
+        "src/com/android/systemui/util/sensors/ThresholdSensor.java",
+    ]
+}
+
 android_library {
     name: "SystemUI-core",
     srcs: [
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7120cc2..52b41a4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -530,6 +530,14 @@
             androidprv:alwaysFocusable="true"
             android:excludeFromRecents="true" />
 
+        <!-- started from TvNotificationPanel -->
+        <activity
+            android:name=".statusbar.tv.notifications.TvNotificationPanelActivity"
+            android:excludeFromRecents="true"
+            android:launchMode="singleTask"
+            android:noHistory="true"
+            android:theme="@style/TvSidePanelTheme" />
+
         <!-- started from SliceProvider -->
         <activity android:name=".SlicePermissionActivity"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 17d2f9c..f884270 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -2,8 +2,11 @@
 
 dsandler@android.com
 
+aaliomer@google.com
 adamcohen@google.com
+alexflo@google.com
 asc@google.com
+awickham@google.com
 beverlyt@google.com
 brockman@google.com
 cinek@google.com
@@ -11,11 +14,16 @@
 dupin@google.com
 ethibodeau@google.com
 evanlaird@google.com
+gwasserman@google.com
 hwwang@google.com
 hyunyoungs@google.com
 jaggies@google.com
+jamesoleary@google.com
+jeffdq@google.com
 jjaggi@google.com
+jonmiranda@google.com
 joshmcgrath@google.com
+joshtrask@google.com
 juliacr@google.com
 juliatuttle@google.com
 kchyn@google.com
@@ -24,28 +32,38 @@
 lynhan@google.com
 madym@google.com
 mankoff@google.com
+mett@google.com
+mkephart@google.com
+mpietal@google.com
 mrcasey@google.com
 mrenouf@google.com
 nbenbernou@google.com
 nesciosquid@google.com
 ogunwale@google.com
 peanutbutter@google.com
+pinyaoting@google.com
 pixel@google.com
 roosa@google.com
+santie@google.com
 snoeberger@google.com
+sreyasr@google.com
 steell@google.com
+sfufa@google.com
 stwu@google.com
 sunnygoyal@google.com
 susikp@google.com
+thiruram@google.com
 tracyzhou@google.com
 tsuji@google.com
 twickham@google.com
+vadimt@google.com
+victortulias@google.com
 winsonc@google.com
+xuqiu@google.com
 zakcohen@google.com
 
 #Android Auto
 hseog@google.com
 
 #Android TV
-rgl@google.com
-
+rgl@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index df5561a..ab4f800 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -19,7 +19,8 @@
     srcs: ["src/**/*.java"],
 
     static_libs: [
-        "PluginCoreLib"
+        "PluginCoreLib",
+        "SystemUI-sensors",
     ],
 
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 0f94bca..6e86f26 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -20,6 +20,7 @@
 import android.view.MotionEvent;
 
 import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.util.sensors.ThresholdSensor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -35,12 +36,6 @@
 
     void onSuccessfulUnlock();
 
-    void onNotificationActive();
-
-    void setShowingAod(boolean showingAod);
-
-    void onNotificatonStartDraggingDown();
-
     boolean isUnlockingDisabled();
 
     /** Returns true if the gesture should be rejected. */
@@ -82,66 +77,21 @@
      */
     boolean isFalseDoubleTap();
 
-    void onNotificatonStopDraggingDown();
-
-    void setNotificationExpanded();
-
     boolean isClassifierEnabled();
 
-    void onQsDown();
-
-    void setQsExpanded(boolean expanded);
-
     boolean shouldEnforceBouncer();
 
-    void onTrackingStarted(boolean secure);
-
-    void onTrackingStopped();
-
-    void onLeftAffordanceOn();
-
-    void onCameraOn();
-
-    void onAffordanceSwipingStarted(boolean rightCorner);
-
-    void onAffordanceSwipingAborted();
-
-    void onStartExpandingFromPulse();
-
-    void onExpansionFromPulseStopped();
-
     Uri reportRejectedTouch();
 
-    void onScreenOnFromTouch();
-
     boolean isReportingEnabled();
 
-    void onUnlockHintStarted();
-
-    void onCameraHintStarted();
-
-    void onLeftAffordanceHintStarted();
-
-    void onScreenTurningOn();
-
-    void onScreenOff();
-
-    void onNotificationStopDismissing();
-
-    void onNotificationDismissed();
-
-    void onNotificationStartDismissing();
-
-    void onNotificationDoubleTap(boolean accepted, float dx, float dy);
-
-    void onBouncerShown();
-
-    void onBouncerHidden();
-
     void onTouchEvent(MotionEvent ev, int width, int height);
 
     /** From com.android.systemui.Dumpable. */
     void dump(FileDescriptor fd, PrintWriter pw, String[] args);
 
     void cleanup();
+
+    /** Call to report a ProximityEvent to the FalsingManager. */
+    void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent);
 }
diff --git a/packages/SystemUI/res-keyguard/drawable/circle_white.xml b/packages/SystemUI/res-keyguard/drawable/circle_white.xml
new file mode 100644
index 0000000..d1b2097
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/circle_white.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <solid android:color="#33FFFFFF" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index b75c2c4..c82bda6 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -95,7 +95,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:gravity="center_horizontal"
-            android:textSize="170dp"
+            android:textSize="180dp"
             android:letterSpacing="0.02"
             android:lineSpacingMultiplier=".8"
             android:includeFontPadding="false"
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index f1c539e..c1e81ba 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -23,7 +23,7 @@
     <!-- Indication when device is not charging due to bad placement on the dock. [CHAR LIMIT=60] -->
     <string name="dock_alignment_not_charging" product="default">Realign phone to charge wirelessly</string>
 
-    <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
+    <!-- Message of the overlay warning the user that the TV is about to go to standby unless a TV remote button is pressed. [CHAR LIMIT=NONE] -->
     <string name="inattentive_sleep_warning_message" product="tv">The Android TV device will soon turn off; press a button to keep it on.</string>
     <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
     <string name="inattentive_sleep_warning_message" product="default">The device will soon turn off; press to keep it on.</string>
diff --git a/packages/SystemUI/res/layout/disabled_udfps_view.xml b/packages/SystemUI/res/layout/disabled_udfps_view.xml
new file mode 100644
index 0000000..aab8661
--- /dev/null
+++ b/packages/SystemUI/res/layout/disabled_udfps_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<com.android.keyguard.DisabledUdfpsView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/disabled_udfps_view"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/circle_white"
+/>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index 7d45de3f..30ffc32 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -1,67 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/global_actions_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
 >
-  <com.android.systemui.globalactions.GlobalActionsFlatLayout
-      android:id="@id/global_actions_view"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="horizontal"
-      android:theme="@style/qs_theme"
-      android:clipChildren="false"
-      android:clipToPadding="false"
-      android:layout_marginStart="@dimen/global_actions_side_margin"
-  >
-    <LinearLayout
-        android:id="@android:id/list"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="@dimen/global_actions_grid_vertical_padding"
-        android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
-        android:orientation="horizontal"
-        android:gravity="left | center_vertical"
-        android:translationZ="@dimen/global_actions_translate"
-    >
-      <RelativeLayout
-          android:id="@+id/global_actions_overflow_button"
-          android:contentDescription="@string/accessibility_menu"
-          android:layout_width="48dp"
-          android:layout_height="48dp"
-      >
-        <ImageView
-            android:src="@drawable/ic_more_vert"
-            android:layout_centerInParent="true"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
-            android:tint="@color/control_more_vert"
-        />
-      </RelativeLayout>
-    </LinearLayout>
-  </com.android.systemui.globalactions.GlobalActionsFlatLayout>
 
-  <androidx.constraintlayout.widget.ConstraintLayout
-      android:id="@+id/global_actions_lock_message_container"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent"
-      android:visibility="gone">
-    <TextView
-        android:id="@+id/global_actions_lock_message"
-        style="@style/TextAppearance.Control.Title"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginHorizontal="@dimen/global_actions_side_margin"
-        android:drawablePadding="12dp"
-        android:gravity="center"
-        android:text="@string/global_action_lock_message"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintVertical_bias="0.35"/>
-  </androidx.constraintlayout.widget.ConstraintLayout>
+  <include layout="@layout/global_actions_view" />
+
+  <include layout="@layout/global_actions_lock_view" />
 
   <com.android.systemui.globalactions.MinHeightScrollView
       android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/global_actions_lock_view.xml b/packages/SystemUI/res/layout/global_actions_lock_view.xml
new file mode 100644
index 0000000..eccc636
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_lock_view.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/global_actions_lock_message_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone">
+  <TextView
+      android:id="@+id/global_actions_lock_message"
+      style="@style/TextAppearance.Control.Title"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_marginHorizontal="@dimen/global_actions_side_margin"
+      android:drawablePadding="12dp"
+      android:gravity="center"
+      android:text="@string/global_action_lock_message"
+      app:layout_constraintBottom_toBottomOf="parent"
+      app:layout_constraintTop_toTopOf="parent"
+      app:layout_constraintVertical_bias="0.35"/>
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_view.xml b/packages/SystemUI/res/layout/global_actions_view.xml
new file mode 100644
index 0000000..454707b
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_view.xml
@@ -0,0 +1,52 @@
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<com.android.systemui.globalactions.GlobalActionsFlatLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/global_actions_view"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:theme="@style/qs_theme"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:layout_marginStart="@dimen/global_actions_side_margin"
+    >
+  <LinearLayout
+      android:id="@android:id/list"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+      android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+      android:orientation="horizontal"
+      android:gravity="left | center_vertical"
+      android:translationZ="@dimen/global_actions_translate"
+      >
+    <RelativeLayout
+        android:id="@+id/global_actions_overflow_button"
+        android:contentDescription="@string/accessibility_menu"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        >
+      <ImageView
+          android:src="@drawable/ic_more_vert"
+          android:layout_centerInParent="true"
+          android:layout_width="24dp"
+          android:layout_height="24dp"
+          android:tint="@color/control_more_vert"
+          />
+    </RelativeLayout>
+  </LinearLayout>
+</com.android.systemui.globalactions.GlobalActionsFlatLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 6c20c1e..2bf41d2 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -40,18 +40,4 @@
         android:visibility="gone"
         android:pointerIcon="crosshair"/>
     <include layout="@layout/global_screenshot_static"/>
-    <FrameLayout
-        android:id="@+id/global_screenshot_dismiss_button"
-        android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
-        android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
-        android:elevation="7dp"
-        android:visibility="gone"
-        android:contentDescription="@string/screenshot_dismiss_description">
-        <ImageView
-            android:id="@+id/global_screenshot_dismiss_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_margin="@dimen/screenshot_dismiss_button_margin"
-            android:src="@drawable/screenshot_cancel"/>
-    </FrameLayout>
 </com.android.systemui.screenshot.ScreenshotView>
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index 096ec7d..9f63c43 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -17,7 +17,6 @@
 <androidx.constraintlayout.widget.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:fitsSystemWindows="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <ImageView
@@ -62,4 +61,22 @@
         </LinearLayout>
     </HorizontalScrollView>
     <include layout="@layout/global_screenshot_preview"/>
+    <FrameLayout
+        android:id="@+id/global_screenshot_dismiss_button"
+        android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
+        android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
+        android:elevation="7dp"
+        android:visibility="gone"
+        app:layout_constraintStart_toEndOf="@id/global_screenshot_preview"
+        app:layout_constraintEnd_toEndOf="@id/global_screenshot_preview"
+        app:layout_constraintTop_toTopOf="@id/global_screenshot_preview"
+        app:layout_constraintBottom_toTopOf="@id/global_screenshot_preview"
+        android:contentDescription="@string/screenshot_dismiss_description">
+        <ImageView
+            android:id="@+id/global_screenshot_dismiss_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="@dimen/screenshot_dismiss_button_margin"
+            android:src="@drawable/screenshot_cancel"/>
+    </FrameLayout>
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index e7c7b5f..13572fa 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -26,11 +26,19 @@
     android:layout_gravity="center_vertical|center_horizontal"
     android:background="@android:color/transparent">
 
+    <ImageView
+        android:id="@+id/primary_footer_icon"
+        android:layout_width="@dimen/qs_footer_icon_size"
+        android:layout_height="@dimen/qs_footer_icon_size"
+        android:gravity="start"
+        android:layout_marginEnd="8dp"
+        android:contentDescription="@null"
+        android:tint="?android:attr/textColorPrimary" />
+
     <com.android.systemui.util.AutoMarqueeTextView
         android:id="@+id/footer_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:gravity="start"
         android:layout_weight="1"
         android:singleLine="true"
         android:ellipsize="marquee"
diff --git a/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml b/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml
index 1a35676..3e40321 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml
@@ -29,8 +29,8 @@
         android:orientation="vertical">
         <ImageView
             android:id="@+id/parental_controls_icon"
-            android:layout_width="36dip"
-            android:layout_height="36dip"
+            android:layout_width="24dip"
+            android:layout_height="24dip"
             android:layout_gravity="center_horizontal"
 
         />
diff --git a/packages/SystemUI/res/layout/tv_notification_item.xml b/packages/SystemUI/res/layout/tv_notification_item.xml
new file mode 100644
index 0000000..711cd4e
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_notification_item.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/tv_notification_panel_width"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:orientation="vertical"
+    android:padding="12dp">
+
+    <TextView
+        android:id="@+id/tv_notification_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="12dp"
+        android:textColor="@color/tv_notification_text_color"
+        android:textSize="18sp" />
+
+    <TextView
+        android:id="@+id/tv_notification_details"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textColor="@color/tv_notification_text_color" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_notification_panel.xml b/packages/SystemUI/res/layout/tv_notification_panel.xml
new file mode 100644
index 0000000..8f00a72
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_notification_panel.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tv_notification_panel"
+    android:layout_width="@dimen/tv_notification_panel_width"
+    android:layout_height="match_parent"
+    android:layout_gravity="end"
+    android:background="@color/tv_notification_background_color"
+    android:orientation="vertical">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="12dp"
+        android:paddingTop="24dp"
+        android:text="@string/tv_notification_panel_title"
+        android:textColor="@color/tv_notification_text_color"
+        android:textSize="24sp"
+        android:textStyle="bold" />
+
+    <TextView
+        android:id="@+id/no_tv_notifications"
+        style="?android:attr/titleTextStyle"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:gravity="top|center"
+        android:paddingTop="24dp"
+        android:text="@string/tv_notification_panel_no_notifications"
+        android:textColor="@color/tv_notification_text_color"
+        android:visibility="gone" />
+
+    <androidx.leanback.widget.VerticalGridView
+        android:id="@+id/notifications_list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index ccd235d..c078805 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
 <com.android.systemui.biometrics.UdfpsView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 09ec439..0c8c5c4 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -29,7 +29,8 @@
         <item>com.android.systemui.util.NotificationChannels</item>
         <item>com.android.systemui.volume.VolumeUI</item>
         <item>com.android.systemui.statusbar.tv.TvStatusBar</item>
-        <item>com.android.systemui.statusbar.tv.TvNotificationPanel</item>
+        <item>com.android.systemui.statusbar.tv.notifications.TvNotificationPanel</item>
+        <item>com.android.systemui.statusbar.tv.notifications.TvNotificationHandler</item>
         <item>com.android.systemui.statusbar.tv.VpnStatusObserver</item>
         <item>com.android.systemui.usb.StorageNotification</item>
         <item>com.android.systemui.power.PowerUI</item>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 9b0ae1d..0961f50 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -33,4 +33,7 @@
     <color name="tv_volume_dialog_seek_bar_background">#A03C4043</color>
     <color name="tv_volume_dialog_seek_bar_fill">#FFF8F9FA</color>
     <color name="tv_volume_dialog_accent">#FFDADCE0</color>
+
+    <color name="tv_notification_background_color">#383838</color>
+    <color name="tv_notification_text_color">#FFFFFF</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 880dd378..01b55b7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -357,9 +357,6 @@
          the notification is not swiped enough to dismiss it. -->
     <bool name="config_showNotificationGear">true</bool>
 
-    <!-- Whether or not a background should be drawn behind a notification. -->
-    <bool name="config_drawNotificationBackground">true</bool>
-
     <!-- Whether or the notifications can be shown and dismissed with a drag. -->
     <bool name="config_enableNotificationShadeDrag">true</bool>
 
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
new file mode 100644
index 0000000..9545bfd
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <dimen name="tv_notification_panel_width">360dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ea1258f..5b74687 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -226,6 +226,8 @@
     <string name="screenshot_saved_text">Tap to view your screenshot</string>
     <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
     <string name="screenshot_failed_title">Couldn\'t save screenshot</string>
+    <!-- Notification text displayed when we fail to save a screenshot due to locked storage. [CHAR LIMIT=100] -->
+    <string name="screenshot_failed_to_save_user_locked_text">Device must be unlocked before screenshot can be saved</string>
     <!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] -->
     <string name="screenshot_failed_to_save_unknown_text">Try taking screenshot again</string>
     <!-- Notification text displayed when we fail to save a screenshot. [CHAR LIMIT=100] -->
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 13271d6..b51cb56 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -26,4 +26,6 @@
     <!-- Disclosure text in the connected notification that indicates that the device is connected to a VPN. The placeholder is the VPN name. [CHAR LIMIT=40] -->
     <string name="notification_disclosure_vpn_text">Via <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g></string>
 
+    <string name="tv_notification_panel_title">Notifications</string>
+    <string name="tv_notification_panel_no_notifications">No Notifications</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml
index 0c4fd23..cb433f3 100644
--- a/packages/SystemUI/res/values/styles_tv.xml
+++ b/packages/SystemUI/res/values/styles_tv.xml
@@ -23,4 +23,12 @@
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:windowDisablePreview">true</item>
      </style>
+
+    <style name="TvSidePanelTheme">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index dd57af3..229d20b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.ActivityTaskManager.getService;
 
 import android.annotation.NonNull;
 import android.app.Activity;
@@ -53,7 +54,6 @@
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -70,6 +70,7 @@
     // Should match the value in AssistManager
     private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
 
+    private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
     private ActivityManagerWrapper() { }
 
     public static ActivityManagerWrapper getInstance() {
@@ -102,29 +103,19 @@
      */
     public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
         // Note: The set of running tasks from the system is ordered by recency
-        try {
-            List<ActivityManager.RunningTaskInfo> tasks =
-                    ActivityTaskManager.getService().getFilteredTasks(1, filterOnlyVisibleRecents);
-            if (tasks.isEmpty()) {
-                return null;
-            }
-            return tasks.get(0);
-        } catch (RemoteException e) {
+        List<ActivityManager.RunningTaskInfo> tasks =
+                mAtm.getTasks(1, filterOnlyVisibleRecents);
+        if (tasks.isEmpty()) {
             return null;
         }
+        return tasks.get(0);
     }
 
     /**
      * @return a list of the recents tasks.
      */
     public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
-        try {
-            return ActivityTaskManager.getService().getRecentTasks(numTasks,
-                            RECENT_IGNORE_UNAVAILABLE, userId).getList();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get recent tasks", e);
-            return new ArrayList<>();
-        }
+        return mAtm.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId);
     }
 
     /**
@@ -133,7 +124,7 @@
     public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
         ActivityManager.TaskSnapshot snapshot = null;
         try {
-            snapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId, isLowResolution);
+            snapshot = getService().getTaskSnapshot(taskId, isLowResolution);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to retrieve task snapshot", e);
         }
@@ -149,8 +140,7 @@
      */
     public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
         try {
-            ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
-                    homeActivity.getActivityToken());
+            getService().invalidateHomeTaskSnapshot(homeActivity.getActivityToken());
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to invalidate home snapshot", e);
         }
@@ -208,7 +198,7 @@
                     }
                 };
             }
-            ActivityTaskManager.getService().startRecentsActivity(intent, eventTime, runner);
+            getService().startRecentsActivity(intent, eventTime, runner);
             return true;
         } catch (Exception e) {
             return false;
@@ -220,7 +210,7 @@
      */
     public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
         try {
-            ActivityTaskManager.getService().cancelRecentsAnimation(restoreHomeRootTaskPosition);
+            getService().cancelRecentsAnimation(restoreHomeRootTaskPosition);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to cancel recents animation", e);
         }
@@ -259,7 +249,7 @@
     public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
         try {
             Bundle optsBundle = options == null ? null : options.toBundle();
-            ActivityTaskManager.getService().startActivityFromRecents(taskId, optsBundle);
+            getService().startActivityFromRecents(taskId, optsBundle);
             return true;
         } catch (Exception e) {
             return false;
@@ -296,7 +286,7 @@
      */
     public void removeTask(final int taskId) {
         try {
-            ActivityTaskManager.getService().removeTask(taskId);
+            getService().removeTask(taskId);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to remove task=" + taskId, e);
         }
@@ -307,7 +297,7 @@
      */
     public void removeAllRecentTasks() {
         try {
-            ActivityTaskManager.getService().removeAllVisibleRecentTasks();
+            getService().removeAllVisibleRecentTasks();
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to remove all tasks", e);
         }
@@ -318,7 +308,7 @@
      */
     public boolean isScreenPinningActive() {
         try {
-            return ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
+            return getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
         } catch (RemoteException e) {
             return false;
         }
@@ -337,7 +327,7 @@
      */
     public boolean isLockToAppActive() {
         try {
-            return ActivityTaskManager.getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+            return getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
         } catch (RemoteException e) {
             return false;
         }
@@ -348,7 +338,7 @@
      */
     public boolean isLockTaskKioskModeActive() {
         try {
-            return ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
+            return getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
         } catch (RemoteException e) {
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
new file mode 100644
index 0000000..f01b67b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
+
+import android.hardware.biometrics.BiometricSourceType;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.util.ViewController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Controls when to show the DisabledUdfpsView to unlock the device on the lockscreen.
+ * If the device is not authenticated, the bouncer will show.
+ *
+ * This tap target will only show when:
+ * - User has UDFPS enrolled
+ * - UDFPS is currently unavailable see {@link KeyguardUpdateMonitor#shouldListenForUdfps}
+ */
+@SysUISingleton
+public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> implements Dumpable {
+    @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @NonNull private final KeyguardViewController mKeyguardViewController;
+    @NonNull private final StatusBarStateController mStatusBarStateController;
+
+    private boolean mIsDozing;
+    private boolean mIsBouncerShowing;
+    private boolean mIsKeyguardShowing;
+    private boolean mRunningFPS;
+    private boolean mAuthenticated;
+
+    private boolean mShowButton;
+
+    public DisabledUdfpsController(
+            @NonNull DisabledUdfpsView view,
+            @NonNull StatusBarStateController statusBarStateController,
+            @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
+            @NonNull AuthController authController,
+            @NonNull KeyguardViewController keyguardViewController
+    ) {
+        super(view);
+        mView.setOnClickListener(mOnClickListener);
+        mView.setSensorProperties(authController.getUdfpsProps().get(0));
+
+        mStatusBarStateController = statusBarStateController;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mKeyguardViewController = keyguardViewController;
+    }
+
+    @Override
+    protected void onViewAttached() {
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+        mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
+
+        mStatusBarStateController.addCallback(mStatusBarStateListener);
+        mIsKeyguardShowing = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+        mIsDozing = mStatusBarStateController.isDozing();
+        mAuthenticated = false;
+    }
+
+    @Override
+    protected void onViewDetached() {
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+        mStatusBarStateController.removeCallback(mStatusBarStateListener);
+    }
+
+    private void updateButtonVisibility() {
+        mShowButton = !mAuthenticated && !mIsDozing && mIsKeyguardShowing
+                && !mIsBouncerShowing && !mRunningFPS;
+        if (mShowButton) {
+            mView.setVisibility(View.VISIBLE);
+        } else {
+            mView.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    @Override
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        pw.println("DisabledUdfpsController state:");
+        pw.println("  mShowBouncerButton: " + mShowButton);
+        pw.println("  mIsDozing: " + mIsDozing);
+        pw.println("  mIsKeyguardShowing: " + mIsKeyguardShowing);
+        pw.println("  mIsBouncerShowing: " + mIsBouncerShowing);
+        pw.println("  mRunningFPS: " + mRunningFPS);
+        pw.println("  mAuthenticated: " + mAuthenticated);
+    }
+
+    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            mKeyguardViewController.showBouncer(/* scrim */ true);
+        }
+    };
+
+    private StatusBarStateController.StateListener mStatusBarStateListener =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onStateChanged(int newState) {
+                    mIsKeyguardShowing = newState == StatusBarState.KEYGUARD;
+                    updateButtonVisibility();
+                }
+
+                @Override
+                public void onDozingChanged(boolean isDozing) {
+                    mIsDozing = isDozing;
+                    updateButtonVisibility();
+                }
+            };
+
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onKeyguardBouncerChanged(boolean bouncer) {
+                    mIsBouncerShowing = bouncer;
+                    updateButtonVisibility();
+                }
+
+                @Override
+                public void onBiometricRunningStateChanged(boolean running,
+                        BiometricSourceType biometricSourceType) {
+                    mRunningFPS = running && biometricSourceType == FINGERPRINT;
+                    updateButtonVisibility();
+                }
+
+                @Override
+                public void onUserUnlocked() {
+                    mAuthenticated = true;
+                    updateButtonVisibility();
+                }
+            };
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
new file mode 100644
index 0000000..d8ab780
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.RectF;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.util.AttributeSet;
+import android.view.Surface;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+/**
+ * A full screen view with an oval target where the UDFPS sensor is.
+ * Controlled by {@link DisabledUdfpsController}.
+ */
+public class DisabledUdfpsView extends Button {
+    @NonNull private final RectF mSensorRect;
+    @NonNull private final Context mContext;
+
+    // Used to obtain the sensor location.
+    @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
+
+    public DisabledUdfpsView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        mSensorRect = new RectF();
+    }
+
+    public void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
+        mSensorProps = properties;
+    }
+
+    // The "h" and "w" are the display's height and width relative to its current rotation.
+    private void updateSensorRect(int h, int w) {
+        // mSensorProps coordinates assume portrait mode.
+        mSensorRect.set(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
+                mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
+                mSensorProps.sensorLocationX + mSensorProps.sensorRadius,
+                mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
+
+        // Transform mSensorRect if the device is in landscape mode.
+        switch (mContext.getDisplay().getRotation()) {
+            case Surface.ROTATION_90:
+                mSensorRect.set(mSensorRect.top, h - mSensorRect.right, mSensorRect.bottom,
+                        h - mSensorRect.left);
+                break;
+            case Surface.ROTATION_270:
+                mSensorRect.set(w - mSensorRect.bottom, mSensorRect.left, w - mSensorRect.top,
+                        mSensorRect.right);
+                break;
+            default:
+                // Do nothing to stay in portrait mode.
+        }
+
+        setX(mSensorRect.left);
+        setY(mSensorRect.top);
+        setLayoutParams(new FrameLayout.LayoutParams(
+                (int) (mSensorRect.right - mSensorRect.left),
+                (int) (mSensorRect.bottom - mSensorRect.top)));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        // Always re-compute the layout regardless of whether "changed" is true. It is usually false
+        // when the device goes from landscape to seascape and vice versa, but mSensorRect and
+        // its dependencies need to be recalculated to stay at the same physical location on the
+        // screen.
+        final int w = getLayoutParams().width;
+        final int h = getLayoutParams().height;
+        updateSensorRect(h, w);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index c5c36e9..829ff97 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -62,6 +62,7 @@
     private AnimatableClockController mNewLockScreenClockViewController;
     private FrameLayout mNewLockScreenClockFrame;
     private AnimatableClockController mNewLockScreenLargeClockViewController;
+    private FrameLayout mNewLockScreenLargeClockFrame;
 
     private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
 
@@ -126,6 +127,7 @@
         mView.updateColors(getGradientColors());
         updateAodIcons();
         mNewLockScreenClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view);
+        mNewLockScreenLargeClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view_large);
     }
 
     @Override
@@ -199,13 +201,18 @@
     /**
      * Update position of the view, with optional animation. Move the slice view and the clock
      * slightly towards the center in order to prevent burn-in. Y positioning occurs at the
-     * view parent level.
+     * view parent level. The large clock view will scale instead of using x position offsets, to
+     * keep the clock centered.
      */
-    void updatePosition(int x, AnimationProperties props, boolean animate) {
+    void updatePosition(int x, float scale, AnimationProperties props, boolean animate) {
         x = Math.abs(x);
         if (mNewLockScreenClockFrame != null) {
             PropertyAnimator.setProperty(mNewLockScreenClockFrame, AnimatableProperty.TRANSLATION_X,
                     -x, props, animate);
+            PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_X,
+                    scale, props, animate);
+            PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_Y,
+                    scale, props, animate);
         }
         mKeyguardSliceViewController.updatePosition(x, props, animate);
         mNotificationIconAreaController.updatePosition(x, props, animate);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index a32cd14..3cbab8e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -244,7 +244,7 @@
                     iconDrawable.setBounds(0, 0, Math.max(width, 1), iconSize);
                 }
             }
-            button.setCompoundDrawables(iconDrawable, null, null, null);
+            button.setCompoundDrawablesRelative(iconDrawable, null, null, null);
             button.setOnClickListener(mOnClickListener);
             button.setClickable(pendingIntent != null);
         }
@@ -536,9 +536,9 @@
         }
 
         @Override
-        public void setCompoundDrawables(Drawable left, Drawable top, Drawable right,
+        public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end,
                 Drawable bottom) {
-            super.setCompoundDrawables(left, top, right, bottom);
+            super.setCompoundDrawablesRelative(start, top, end, bottom);
             updateDrawableColors();
             updatePadding();
         }
@@ -558,9 +558,9 @@
         public void setLockScreenMode(int mode) {
             mLockScreenMode = mode;
             if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
-                setGravity(Gravity.START);
+                setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
             } else {
-                setGravity(Gravity.CENTER);
+                setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
             }
             updatePadding();
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index c0e06e8..bc81a198 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -193,7 +193,7 @@
     /**
      * Update position of the view with an optional animation
      */
-    public void updatePosition(int x, int y, boolean animate) {
+    public void updatePosition(int x, int y, float scale, boolean animate) {
         PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES,
                 animate);
 
@@ -202,10 +202,12 @@
             PropertyAnimator.setProperty(mView, AnimatableProperty.X, 0,
                     CLOCK_ANIMATION_PROPERTIES, animate);
 
-            mKeyguardClockSwitchController.updatePosition(x, CLOCK_ANIMATION_PROPERTIES, animate);
+            mKeyguardClockSwitchController.updatePosition(x, scale, CLOCK_ANIMATION_PROPERTIES,
+                    animate);
         } else {
             // reset any prior movement
-            mKeyguardClockSwitchController.updatePosition(0, CLOCK_ANIMATION_PROPERTIES, animate);
+            mKeyguardClockSwitchController.updatePosition(0, 0f, CLOCK_ANIMATION_PROPERTIES,
+                    animate);
 
             PropertyAnimator.setProperty(mView, AnimatableProperty.X, x,
                     CLOCK_ANIMATION_PROPERTIES, animate);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 611131f..a7e5195 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1925,6 +1925,7 @@
         }
 
         // TODO: Add support for multiple fingerprint sensors, b/173730729
+        updateUdfpsEnrolled(getCurrentUser());
         boolean shouldListenForFingerprint =
                 isUdfpsEnrolled() ? shouldListenForUdfps() : shouldListenForFingerprint();
         boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
@@ -2137,7 +2138,6 @@
         }
         if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
         int userId = getCurrentUser();
-        updateUdfpsEnrolled(userId);
         if (isUnlockWithFingerprintPossible(userId)) {
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
@@ -2627,7 +2627,6 @@
         Assert.isMainThread();
         if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncerVisible + ")");
         mBouncer = bouncerVisible == 1;
-
         if (mBouncer) {
             // If the bouncer is shown, always clear this flag. This can happen in the following
             // situations: 1) Default camera with SHOW_WHEN_LOCKED is not chosen yet. 2) Secure
diff --git a/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
index f5e01de..0d41a2f 100644
--- a/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
+++ b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
@@ -19,8 +19,9 @@
 import android.graphics.Paint
 import android.graphics.fonts.Font
 import android.graphics.text.PositionedGlyphs
-import android.graphics.text.TextRunShaper
 import android.text.Layout
+import android.text.TextPaint
+import android.text.TextShaper
 import android.util.MathUtils
 import com.android.internal.graphics.ColorUtils
 import java.lang.Math.max
@@ -57,10 +58,10 @@
      */
     val targetPaint = createDefaultPaint(layout.paint, lines)
 
-    private fun createDefaultPaint(paint: Paint, lines: Int): ArrayList<Paint> {
-        val paintList = ArrayList<Paint>()
+    private fun createDefaultPaint(paint: TextPaint, lines: Int): ArrayList<TextPaint> {
+        val paintList = ArrayList<TextPaint>()
         for (i in 0 until lines)
-            paintList.add(Paint(paint))
+            paintList.add(TextPaint(paint))
         return paintList
     }
 
@@ -79,9 +80,9 @@
     }
 
     /**
-     * A class represents text layout of a single line.
+     * A class represents text layout of a single run.
      */
-    private class Line(
+    private class Run(
         val glyphIds: IntArray,
         val baseX: FloatArray, // same length as glyphIds
         val baseY: FloatArray, // same length as glyphIds
@@ -90,11 +91,18 @@
         val fontRuns: List<FontRun>
     )
 
+    /**
+     * A class represents text layout of a single line.
+     */
+    private class Line(
+        val runs: List<Run>
+    )
+
     private var lines = listOf<Line>()
     private val fontInterpolator = FontInterpolator()
 
     // Recycling object for glyph drawing. Will be extended for the longest font run if needed.
-    private val tmpDrawPaints = ArrayList<Paint>()
+    private val tmpDrawPaints = ArrayList<TextPaint>()
     private var tmpPositionArray = FloatArray(20)
 
     /**
@@ -215,12 +223,14 @@
         }
 
         lines.forEach { line ->
-            for (i in line.baseX.indices) {
-                line.baseX[i] = MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
-                line.baseY[i] = MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
-            }
-            line.fontRuns.forEach {
-                it.baseFont = fontInterpolator.lerp(it.baseFont, it.targetFont, progress)
+            line.runs.forEach { run ->
+                for (i in run.baseX.indices) {
+                    run.baseX[i] = MathUtils.lerp(run.baseX[i], run.targetX[i], progress)
+                    run.baseY[i] = MathUtils.lerp(run.baseY[i], run.targetY[i], progress)
+                }
+                run.fontRuns.forEach {
+                    it.baseFont = fontInterpolator.lerp(it.baseFont, it.targetFont, progress)
+                }
             }
         }
 
@@ -228,10 +238,10 @@
     }
 
     companion object {
-        fun updatePaint(toUpdate: ArrayList<Paint>, newValues: ArrayList<Paint>) {
+        fun updatePaint(toUpdate: ArrayList<TextPaint>, newValues: ArrayList<TextPaint>) {
             toUpdate.clear()
             for (paint in newValues)
-                toUpdate.add(Paint(paint))
+                toUpdate.add(TextPaint(paint))
         }
     }
 
@@ -243,20 +253,22 @@
     fun draw(canvas: Canvas) {
         lerp(basePaint, targetPaint, progress, tmpDrawPaints)
         lines.forEachIndexed { lineNo, line ->
-            canvas.save()
-            try {
-                // Move to drawing origin.
-                val origin = layout.getDrawOrigin(lineNo)
-                canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
+            line.runs.forEach { run ->
+                canvas.save()
+                try {
+                    // Move to drawing origin.
+                    val origin = layout.getDrawOrigin(lineNo)
+                    canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
 
-                line.fontRuns.forEach { run ->
-                    if (lineNo >= tmpDrawPaints.size)
-                        drawFontRun(canvas, line, run, tmpDrawPaints[0])
-                    else
-                        drawFontRun(canvas, line, run, tmpDrawPaints[lineNo])
+                    run.fontRuns.forEach { fontRun ->
+                        if (lineNo >= tmpDrawPaints.size)
+                            drawFontRun(canvas, run, fontRun, tmpDrawPaints[0])
+                        else
+                            drawFontRun(canvas, run, fontRun, tmpDrawPaints[lineNo])
+                    }
+                } finally {
+                    canvas.restore()
                 }
-            } finally {
-                canvas.restore()
             }
         }
     }
@@ -271,64 +283,68 @@
         }
 
         var maxRunLength = 0
-        lines = baseLayout.zip(targetLayout) { base, target ->
-            require(base.glyphCount() == target.glyphCount()) {
-                "Inconsistent glyph count at line ${lines.size}"
-            }
+        lines = baseLayout.zip(targetLayout) { baseLine, targetLine ->
+            val runs = baseLine.zip(targetLine) { base, target ->
 
-            val glyphCount = base.glyphCount()
-
-            // Good to recycle the array if the existing array can hold the new layout result.
-            val glyphIds = IntArray(glyphCount) {
-                base.getGlyphId(it).also { baseGlyphId ->
-                    require(baseGlyphId == target.getGlyphId(it)) {
-                        "Inconsistent glyph ID at $it in line ${lines.size}"
-                    }
-                }
-            }
-
-            val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
-            val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
-            val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
-            val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
-
-            // Calculate font runs
-            val fontRun = mutableListOf<FontRun>()
-            if (glyphCount != 0) {
-                var start = 0
-                var baseFont = base.getFont(start)
-                var targetFont = target.getFont(start)
-                require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
-                    "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+                require(base.glyphCount() == target.glyphCount()) {
+                    "Inconsistent glyph count at line ${lines.size}"
                 }
 
-                for (i in 1 until glyphCount) {
-                    val nextBaseFont = base.getFont(i)
-                    val nextTargetFont = target.getFont(i)
+                val glyphCount = base.glyphCount()
 
-                    if (baseFont !== nextBaseFont) {
-                        require(targetFont !== nextTargetFont) {
-                            "Base font has changed at $i but target font has not changed."
-                        }
-                        // Font transition point. push run and reset context.
-                        fontRun.add(FontRun(start, i, baseFont, targetFont))
-                        maxRunLength = max(maxRunLength, i - start)
-                        baseFont = nextBaseFont
-                        targetFont = nextTargetFont
-                        start = i
-                        require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
-                            "Cannot interpolate font at $start ($baseFont vs $targetFont)"
-                        }
-                    } else { // baseFont === nextBaseFont
-                        require(targetFont === nextTargetFont) {
-                            "Base font has not changed at $i but target font has changed."
+                // Good to recycle the array if the existing array can hold the new layout result.
+                val glyphIds = IntArray(glyphCount) {
+                    base.getGlyphId(it).also { baseGlyphId ->
+                        require(baseGlyphId == target.getGlyphId(it)) {
+                            "Inconsistent glyph ID at $it in line ${lines.size}"
                         }
                     }
                 }
-                fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
-                maxRunLength = max(maxRunLength, glyphCount - start)
+
+                val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
+                val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
+                val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
+                val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
+
+                // Calculate font runs
+                val fontRun = mutableListOf<FontRun>()
+                if (glyphCount != 0) {
+                    var start = 0
+                    var baseFont = base.getFont(start)
+                    var targetFont = target.getFont(start)
+                    require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+                        "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+                    }
+
+                    for (i in 1 until glyphCount) {
+                        val nextBaseFont = base.getFont(i)
+                        val nextTargetFont = target.getFont(i)
+
+                        if (baseFont !== nextBaseFont) {
+                            require(targetFont !== nextTargetFont) {
+                                "Base font has changed at $i but target font has not changed."
+                            }
+                            // Font transition point. push run and reset context.
+                            fontRun.add(FontRun(start, i, baseFont, targetFont))
+                            maxRunLength = max(maxRunLength, i - start)
+                            baseFont = nextBaseFont
+                            targetFont = nextTargetFont
+                            start = i
+                            require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+                                "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+                            }
+                        } else { // baseFont === nextBaseFont
+                            require(targetFont === nextTargetFont) {
+                                "Base font has not changed at $i but target font has changed."
+                            }
+                        }
+                    }
+                    fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
+                    maxRunLength = max(maxRunLength, glyphCount - start)
+                }
+                Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
             }
-            Line(glyphIds, baseX, baseY, targetX, targetY, fontRun)
+            Line(runs)
         }
 
         // Update float array used for drawing.
@@ -338,7 +354,7 @@
     }
 
     // Draws single font run.
-    private fun drawFontRun(c: Canvas, line: Line, run: FontRun, paint: Paint) {
+    private fun drawFontRun(c: Canvas, line: Run, run: FontRun, paint: Paint) {
         var arrayIndex = 0
         for (i in run.start until run.end) {
             tmpPositionArray[arrayIndex++] =
@@ -358,7 +374,7 @@
     }
 
     private fun updatePositionsAndFonts(
-        layoutResult: List<PositionedGlyphs>,
+        layoutResult: List<List<PositionedGlyphs>>,
         updateBase: Boolean
     ) {
         // Update target positions with newly calculated text layout.
@@ -366,45 +382,48 @@
             "The new layout result has different line count."
         }
 
-        lines.zip(layoutResult) { line, newGlyphs ->
-            require(newGlyphs.glyphCount() == line.glyphIds.size) {
-                "The new layout has different glyph count."
-            }
-
-            line.fontRuns.forEach { run ->
-                val newFont = newGlyphs.getFont(run.start)
-                for (i in run.start until run.end) {
-                    require(newGlyphs.getGlyphId(run.start) == line.glyphIds[run.start]) {
-                        "The new layout has different glyph ID at ${run.start}"
-                    }
-                    require(newFont === newGlyphs.getFont(i)) {
-                        "The new layout has different font run." +
-                                " $newFont vs ${newGlyphs.getFont(i)} at $i"
-                    }
+        lines.zip(layoutResult) { line, runs ->
+            line.runs.zip(runs) { lineRun, newGlyphs ->
+                require(newGlyphs.glyphCount() == lineRun.glyphIds.size) {
+                    "The new layout has different glyph count."
                 }
 
-                // The passing base font and target font is already interpolatable, so just check
-                // new font can be interpolatable with base font.
-                require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
-                    "New font cannot be interpolated with existing font. $newFont, ${run.baseFont}"
+                lineRun.fontRuns.forEach { run ->
+                    val newFont = newGlyphs.getFont(run.start)
+                    for (i in run.start until run.end) {
+                        require(newGlyphs.getGlyphId(run.start) == lineRun.glyphIds[run.start]) {
+                            "The new layout has different glyph ID at ${run.start}"
+                        }
+                        require(newFont === newGlyphs.getFont(i)) {
+                            "The new layout has different font run." +
+                                    " $newFont vs ${newGlyphs.getFont(i)} at $i"
+                        }
+                    }
+
+                    // The passing base font and target font is already interpolatable, so just
+                    // check new font can be interpolatable with base font.
+                    require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
+                        "New font cannot be interpolated with existing font. $newFont," +
+                                " ${run.baseFont}"
+                    }
+
+                    if (updateBase) {
+                        run.baseFont = newFont
+                    } else {
+                        run.targetFont = newFont
+                    }
                 }
 
                 if (updateBase) {
-                    run.baseFont = newFont
+                    for (i in lineRun.baseX.indices) {
+                        lineRun.baseX[i] = newGlyphs.getGlyphX(i)
+                        lineRun.baseY[i] = newGlyphs.getGlyphY(i)
+                    }
                 } else {
-                    run.targetFont = newFont
-                }
-            }
-
-            if (updateBase) {
-                for (i in line.baseX.indices) {
-                    line.baseX[i] = newGlyphs.getGlyphX(i)
-                    line.baseY[i] = newGlyphs.getGlyphY(i)
-                }
-            } else {
-                for (i in line.baseX.indices) {
-                    line.targetX[i] = newGlyphs.getGlyphX(i)
-                    line.targetY[i] = newGlyphs.getGlyphY(i)
+                    for (i in lineRun.baseX.indices) {
+                        lineRun.targetX[i] = newGlyphs.getGlyphX(i)
+                        lineRun.targetY[i] = newGlyphs.getGlyphY(i)
+                    }
                 }
             }
         }
@@ -412,16 +431,16 @@
 
     // Linear interpolate the paint.
     private fun lerp(
-        from: ArrayList<Paint>,
-        to: ArrayList<Paint>,
+        from: ArrayList<TextPaint>,
+        to: ArrayList<TextPaint>,
         progress: Float,
-        out: ArrayList<Paint>
+        out: ArrayList<TextPaint>
     ) {
         out.clear()
         // Currently only font size & colors are interpolated.
         // TODO(172943390): Add other interpolation or support custom interpolator.
         for (index in from.indices) {
-            val paint = Paint(from[index])
+            val paint = TextPaint(from[index])
             paint.textSize = MathUtils.lerp(from[index].textSize, to[index].textSize, progress)
             paint.color = ColorUtils.blendARGB(from[index].color, to[index].color, progress)
             out.add(paint)
@@ -429,18 +448,20 @@
     }
 
     // Shape the text and stores the result to out argument.
-    private fun shapeText(layout: Layout, paints: ArrayList<Paint>): List<PositionedGlyphs> {
-        val out = mutableListOf<PositionedGlyphs>()
+    private fun shapeText(
+        layout: Layout,
+        paints: ArrayList<TextPaint>
+    ): List<List<PositionedGlyphs>> {
+        val out = mutableListOf<List<PositionedGlyphs>>()
         for (lineNo in 0 until layout.lineCount) { // Shape all lines.
             val lineStart = layout.getLineStart(lineNo)
             val count = layout.getLineEnd(lineNo) - lineStart
-            out.add(TextRunShaper.shapeTextRun(
-                    layout.text, // Styles are ignored.
-                    lineStart, count, // shape range
-                    lineStart, count, // shape context = shape range.
-                    0f, 0f, // the layout offset. Not changed.
-                    layout.getParagraphDirection(lineNo) == Layout.DIR_RIGHT_TO_LEFT,
-                    paints[lineNo])) // Use given paint instead of layout's for style interpolation.
+            val runs = mutableListOf<PositionedGlyphs>()
+            TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
+                    paints[lineNo]) { _, _, glyphs, _ ->
+                runs.add(glyphs)
+            }
+            out.add(runs)
         }
         return out
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6151ac7..3852b24 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -327,8 +327,8 @@
                     if (Math.abs(delta) > pagingTouchSlop
                             && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
                         if (mCallback.canChildBeDragged(mTouchedView)) {
-                            mCallback.onBeginDrag(mTouchedView);
                             mIsSwiping = true;
+                            mCallback.onBeginDrag(mTouchedView);
                             mInitialTouchPos = getPos(ev);
                             mTranslation = getTranslation(mTouchedView);
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 8e5e9ea..6b4e8bd 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -113,8 +113,10 @@
                     .setShellCommandHandler(mWMComponent.getShellCommandHandler())
                     .setAppPairs(mWMComponent.getAppPairs());
         } else {
-            // TODO: Call on prepareSysUIComponentBuilder but not with real components.
-            builder = builder.setPip(Optional.ofNullable(null))
+            // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
+            // is separating this logic into newly creating SystemUITestsFactory.
+            builder = prepareSysUIComponentBuilder(builder, mWMComponent)
+                    .setPip(Optional.ofNullable(null))
                     .setSplitScreen(Optional.ofNullable(null))
                     .setOneHanded(Optional.ofNullable(null))
                     .setBubbles(Optional.ofNullable(null))
@@ -194,4 +196,4 @@
             AssetManager am, String modelName) {
         return new BackGestureTfClassifierProvider();
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 182b3e1..935f893 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -281,7 +281,7 @@
 
         // Inflate biometric view only if necessary.
         if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) {
-            if (config.mSensorIds.length == 1) {
+            if (config.mSensorIds.length == 1 || config.mSensorIds.length == 2) {
                 final int singleSensorAuthId = config.mSensorIds[0];
                 if (Utils.containsSensorId(mFpProps, singleSensorAuthId)) {
                     FingerprintSensorPropertiesInternal sensorProps = null;
@@ -313,7 +313,6 @@
                     return;
                 }
             } else {
-                // The UI currently only supports authentication with a single sensor.
                 Log.e(TAG, "Unsupported sensor array, length: " + config.mSensorIds.length);
                 mBiometricView = null;
                 mBackgroundView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index dc841d9..9edfee7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -22,6 +22,7 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.app.TaskStackListener;
 import android.content.BroadcastReceiver;
@@ -74,7 +75,7 @@
 
     private final CommandQueue mCommandQueue;
     private final StatusBarStateController mStatusBarStateController;
-    private final IActivityTaskManager mActivityTaskManager;
+    private final ActivityTaskManager mActivityTaskManager;
     @Nullable private final FingerprintManager mFingerprintManager;
     @Nullable private final FaceManager mFaceManager;
     private final Provider<UdfpsController> mUdfpsControllerFactory;
@@ -313,7 +314,7 @@
     @Inject
     public AuthController(Context context, CommandQueue commandQueue,
             StatusBarStateController statusBarStateController,
-            IActivityTaskManager activityTaskManager,
+            ActivityTaskManager activityTaskManager,
             @Nullable FingerprintManager fingerprintManager,
             @Nullable FaceManager faceManager,
             Provider<UdfpsController> udfpsControllerFactory) {
@@ -356,12 +357,8 @@
             mUdfpsController = mUdfpsControllerFactory.get();
         }
 
-        try {
-            mTaskStackListener = new BiometricTaskStackListener();
-            mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Unable to register task stack listener", e);
-        }
+        mTaskStackListener = new BiometricTaskStackListener();
+        mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
     }
 
     @Override
@@ -413,6 +410,11 @@
         mCurrentDialog.onHelp(message);
     }
 
+    @Nullable
+    public List<FingerprintSensorPropertiesInternal> getUdfpsProps() {
+        return mUdfpsProps;
+    }
+
     private String getErrorString(int modality, int error, int vendorCode) {
         switch (modality) {
             case TYPE_FACE:
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
new file mode 100644
index 0000000..c05ce93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+/**
+ * Defines a class that can be used to ingest system events for later processing.
+ */
+public interface FalsingCollector {
+    /** */
+    void onSuccessfulUnlock();
+
+    /** */
+    void onNotificationActive();
+
+    /** */
+    void setShowingAod(boolean showingAod);
+
+    /** */
+    void onNotificationStartDraggingDown();
+
+    /** */
+    void onNotificationStopDraggingDown();
+
+    /** */
+    void setNotificationExpanded();
+
+    /** */
+    void onQsDown();
+
+    /** */
+    void setQsExpanded(boolean expanded);
+
+    /** */
+    boolean shouldEnforceBouncer();
+
+    /** */
+    void onTrackingStarted(boolean secure);
+
+    /** */
+    void onTrackingStopped();
+
+    /** */
+    void onLeftAffordanceOn();
+
+    /** */
+    void onCameraOn();
+
+    /** */
+    void onAffordanceSwipingStarted(boolean rightCorner);
+
+    /** */
+    void onAffordanceSwipingAborted();
+
+    /** */
+    void onStartExpandingFromPulse();
+
+    /** */
+    void onExpansionFromPulseStopped();
+
+    /** */
+    void onScreenOnFromTouch();
+
+    /** */
+    boolean isReportingEnabled();
+
+    /** */
+    void onUnlockHintStarted();
+
+    /** */
+    void onCameraHintStarted();
+
+    /** */
+    void onLeftAffordanceHintStarted();
+
+    /** */
+    void onScreenTurningOn();
+
+    /** */
+    void onScreenOff();
+
+    /** */
+    void onNotificationStopDismissing();
+
+    /** */
+    void onNotificationDismissed();
+
+    /** */
+    void onNotificationStartDismissing();
+
+    /** */
+    void onNotificationDoubleTap(boolean accepted, float dx, float dy);
+
+    /** */
+    void onBouncerShown();
+
+    /** */
+    void onBouncerHidden();
+
+    /** */
+    void onTouchEvent(MotionEvent ev, int width, int height);
+
+    /** */
+    void cleanup();
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
new file mode 100644
index 0000000..a569111
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+/** */
+public class FalsingCollectorFake implements FalsingCollector {
+    @Override
+    public void onSuccessfulUnlock() {
+    }
+
+    @Override
+    public void onNotificationActive() {
+    }
+
+    @Override
+    public void setShowingAod(boolean showingAod) {
+    }
+
+    @Override
+    public void onNotificationStartDraggingDown() {
+    }
+
+    @Override
+    public void onNotificationStopDraggingDown() {
+    }
+
+    @Override
+    public void setNotificationExpanded() {
+    }
+
+    @Override
+    public void onQsDown() {
+    }
+
+    @Override
+    public void setQsExpanded(boolean expanded) {
+    }
+
+    @Override
+    public boolean shouldEnforceBouncer() {
+        return false;
+    }
+
+    @Override
+    public void onTrackingStarted(boolean secure) {
+    }
+
+    @Override
+    public void onTrackingStopped() {
+    }
+
+    @Override
+    public void onLeftAffordanceOn() {
+    }
+
+    @Override
+    public void onCameraOn() {
+    }
+
+    @Override
+    public void onAffordanceSwipingStarted(boolean rightCorner) {
+    }
+
+    @Override
+    public void onAffordanceSwipingAborted() {
+    }
+
+    @Override
+    public void onStartExpandingFromPulse() {
+    }
+
+    @Override
+    public void onExpansionFromPulseStopped() {
+    }
+
+    @Override
+    public void onScreenOnFromTouch() {
+    }
+
+    @Override
+    public boolean isReportingEnabled() {
+        return false;
+    }
+
+    @Override
+    public void onUnlockHintStarted() {
+    }
+
+    @Override
+    public void onCameraHintStarted() {
+    }
+
+    @Override
+    public void onLeftAffordanceHintStarted() {
+    }
+
+    @Override
+    public void onScreenTurningOn() {
+    }
+
+    @Override
+    public void onScreenOff() {
+    }
+
+    @Override
+    public void onNotificationStopDismissing() {
+    }
+
+    @Override
+    public void onNotificationDismissed() {
+    }
+
+    @Override
+    public void onNotificationStartDismissing() {
+    }
+
+    @Override
+    public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
+    }
+
+    @Override
+    public void onBouncerShown() {
+    }
+
+    @Override
+    public void onBouncerHidden() {
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent ev, int width, int height) {
+    }
+
+    @Override
+    public void cleanup() {
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
new file mode 100644
index 0000000..3547392
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import android.hardware.SensorManager;
+import android.hardware.biometrics.BiometricSourceType;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.util.sensors.ProximitySensor;
+import com.android.systemui.util.sensors.ThresholdSensor;
+
+import javax.inject.Inject;
+
+@SysUISingleton
+class FalsingCollectorImpl implements FalsingCollector {
+
+    private static final boolean DEBUG = false;
+    private static final String TAG = "FalsingManager";
+    private static final String PROXIMITY_SENSOR_TAG = "FalsingManager";
+
+    private final FalsingDataProvider mFalsingDataProvider;
+    private final FalsingManager mFalsingManager;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final ProximitySensor mProximitySensor;
+    private final StatusBarStateController mStatusBarStateController;
+
+    private int mState;
+    private boolean mShowingAod;
+    private boolean mScreenOn;
+    private boolean mSessionStarted;
+
+    private final ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent;
+
+    private final StatusBarStateController.StateListener mStatusBarStateListener =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onStateChanged(int newState) {
+                    logDebug("StatusBarState=" + StatusBarState.toShortString(newState));
+                    mState = newState;
+                    updateSessionActive();
+                }
+            };
+
+
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onBiometricAuthenticated(int userId,
+                        BiometricSourceType biometricSourceType,
+                        boolean isStrongBiometric) {
+                    if (userId == KeyguardUpdateMonitor.getCurrentUser()
+                            && biometricSourceType == BiometricSourceType.FACE) {
+                        mFalsingDataProvider.setJustUnlockedWithFace(true);
+                    }
+                }
+            };
+
+    @Inject
+    FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            ProximitySensor proximitySensor, StatusBarStateController statusBarStateController) {
+        mFalsingDataProvider = falsingDataProvider;
+        mFalsingManager = falsingManager;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mProximitySensor = proximitySensor;
+        mStatusBarStateController = statusBarStateController;
+
+
+        mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
+        mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME);
+
+        mStatusBarStateController.addCallback(mStatusBarStateListener);
+        mState = mStatusBarStateController.getState();
+
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+    }
+
+    @Override
+    public void onSuccessfulUnlock() {
+        mFalsingManager.onSuccessfulUnlock();
+        sessionEnd();
+    }
+
+    @Override
+    public void onNotificationActive() {
+    }
+
+    @Override
+    public void setShowingAod(boolean showingAod) {
+        mShowingAod = showingAod;
+        updateSessionActive();
+    }
+
+    @Override
+    public void onNotificationStartDraggingDown() {
+        updateInteractionType(Classifier.NOTIFICATION_DRAG_DOWN);
+    }
+
+    @Override
+    public void onNotificationStopDraggingDown() {
+    }
+
+    @Override
+    public void setNotificationExpanded() {
+    }
+
+    @Override
+    public void onQsDown() {
+        updateInteractionType(Classifier.QUICK_SETTINGS);
+    }
+
+    @Override
+    public void setQsExpanded(boolean expanded) {
+        if (expanded) {
+            unregisterSensors();
+        } else if (mSessionStarted) {
+            registerSensors();
+        }
+    }
+
+    @Override
+    public boolean shouldEnforceBouncer() {
+        return false;
+    }
+
+    @Override
+    public void onTrackingStarted(boolean secure) {
+        updateInteractionType(secure ? Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
+    }
+
+    @Override
+    public void onTrackingStopped() {
+    }
+
+    @Override
+    public void onLeftAffordanceOn() {
+    }
+
+    @Override
+    public void onCameraOn() {
+    }
+
+    @Override
+    public void onAffordanceSwipingStarted(boolean rightCorner) {
+        updateInteractionType(
+                rightCorner ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE);
+    }
+
+    @Override
+    public void onAffordanceSwipingAborted() {
+    }
+
+    @Override
+    public void onStartExpandingFromPulse() {
+        updateInteractionType(Classifier.PULSE_EXPAND);
+    }
+
+    @Override
+    public void onExpansionFromPulseStopped() {
+    }
+
+    @Override
+    public void onScreenOnFromTouch() {
+        onScreenTurningOn();
+    }
+
+    @Override
+    public boolean isReportingEnabled() {
+        return false;
+    }
+
+    @Override
+    public void onUnlockHintStarted() {
+    }
+
+    @Override
+    public void onCameraHintStarted() {
+    }
+
+    @Override
+    public void onLeftAffordanceHintStarted() {
+    }
+
+    @Override
+    public void onScreenTurningOn() {
+        mScreenOn = true;
+        updateSessionActive();
+    }
+
+    @Override
+    public void onScreenOff() {
+        mScreenOn = false;
+        updateSessionActive();
+    }
+
+    @Override
+    public void onNotificationStopDismissing() {
+    }
+
+    @Override
+    public void onNotificationDismissed() {
+    }
+
+    @Override
+    public void onNotificationStartDismissing() {
+        updateInteractionType(Classifier.NOTIFICATION_DISMISS);
+    }
+
+    @Override
+    public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
+    }
+
+    @Override
+    public void onBouncerShown() {
+        unregisterSensors();
+    }
+
+    @Override
+    public void onBouncerHidden() {
+        if (mSessionStarted) {
+            registerSensors();
+        }
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent ev, int width, int height) {
+        mFalsingDataProvider.onMotionEvent(ev);
+        mFalsingManager.onTouchEvent(ev, width, height);
+    }
+
+    @Override
+    public void cleanup() {
+        unregisterSensors();
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
+        mStatusBarStateController.removeCallback(mStatusBarStateListener);
+    }
+
+    private void updateInteractionType(@Classifier.InteractionType int type) {
+        logDebug("InteractionType: " + type);
+        mFalsingDataProvider.setInteractionType(type);
+    }
+
+    private boolean shouldSessionBeActive() {
+        return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
+    }
+
+    private void updateSessionActive() {
+        if (shouldSessionBeActive()) {
+            sessionStart();
+        } else {
+            sessionEnd();
+        }
+    }
+
+    private void sessionStart() {
+        if (!mSessionStarted && shouldSessionBeActive()) {
+            logDebug("Starting Session");
+            mSessionStarted = true;
+            mFalsingDataProvider.setJustUnlockedWithFace(false);
+            registerSensors();
+            mFalsingDataProvider.onSessionStarted();
+        }
+    }
+
+    private void sessionEnd() {
+        if (mSessionStarted) {
+            logDebug("Ending Session");
+            mSessionStarted = false;
+            unregisterSensors();
+            mFalsingDataProvider.onSessionEnd();
+        }
+    }
+
+    private void registerSensors() {
+        if (!mFalsingDataProvider.isWirelessCharging()) {
+            mProximitySensor.register(mSensorEventListener);
+        }
+    }
+
+    private void unregisterSensors() {
+        mProximitySensor.unregister(mSensorEventListener);
+    }
+
+    private void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+        // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
+        // make these calls.
+        mFalsingManager.onProximityEvent(proximityEvent);
+    }
+
+
+    static void logDebug(String msg) {
+        logDebug(msg, null);
+    }
+
+    static void logDebug(String msg, Throwable throwable) {
+        if (DEBUG) {
+            Log.d(TAG, msg, throwable);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
similarity index 72%
rename from packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
rename to packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 4681f97..b29871c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
 
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
 
-import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
+import com.android.systemui.classifier.brightline.FalsingClassifier;
+import com.android.systemui.classifier.brightline.TimeLimitedMotionEventBuffer;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.time.SystemClock;
 
@@ -36,6 +39,7 @@
 /**
  * Acts as a cache and utility class for FalsingClassifiers.
  */
+@SysUISingleton
 public class FalsingDataProvider {
 
     private static final long MOTION_EVENT_AGE_MS = 1000;
@@ -48,6 +52,7 @@
     private final SystemClock mSystemClock;
     private final float mXdpi;
     private final float mYdpi;
+    private final List<SessionListener> mSessionListeners = new ArrayList<>();
 
     private @Classifier.InteractionType int mInteractionType;
     private final Deque<TimeLimitedMotionEventBuffer> mExtendedMotionEvents = new LinkedList<>();
@@ -57,9 +62,9 @@
     private boolean mDirty = true;
 
     private float mAngle = 0;
-    private MotionEvent mFirstActualMotionEvent;
     private MotionEvent mFirstRecentMotionEvent;
     private MotionEvent mLastMotionEvent;
+    private boolean mJustUnlockedWithFace;
 
     @Inject
     public FalsingDataProvider(DisplayMetrics displayMetrics, BatteryController batteryController,
@@ -76,10 +81,6 @@
     }
 
     void onMotionEvent(MotionEvent motionEvent) {
-        if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mFirstActualMotionEvent = motionEvent;
-        }
-
         List<MotionEvent> motionEvents = unpackMotionEvent(motionEvent);
         FalsingClassifier.logDebug("Unpacked into: " + motionEvents.size());
         if (BrightLineFalsingManager.DEBUG) {
@@ -103,29 +104,29 @@
     }
 
     /** Returns screen width in pixels. */
-    int getWidthPixels() {
+    public int getWidthPixels() {
         return mWidthPixels;
     }
 
     /** Returns screen height in pixels. */
-    int getHeightPixels() {
+    public int getHeightPixels() {
         return mHeightPixels;
     }
 
-    float getXdpi() {
+    public float getXdpi() {
         return mXdpi;
     }
 
-    float getYdpi() {
+    public float getYdpi() {
         return mYdpi;
     }
 
-    List<MotionEvent> getRecentMotionEvents() {
+    public List<MotionEvent> getRecentMotionEvents() {
         return mRecentMotionEvents;
     }
 
     /** Returns recent gestures, exclusive of the most recent gesture. Newer gestures come first. */
-    Queue<? extends List<MotionEvent>> getHistoricalMotionEvents() {
+    public Queue<? extends List<MotionEvent>> getHistoricalMotionEvents() {
         long nowMs = mSystemClock.uptimeMillis();
 
         mExtendedMotionEvents.removeIf(
@@ -137,31 +138,38 @@
     /**
      * interactionType is defined by {@link com.android.systemui.classifier.Classifier}.
      */
-    final void setInteractionType(@Classifier.InteractionType int interactionType) {
+    public final void setInteractionType(@Classifier.InteractionType int interactionType) {
         if (mInteractionType != interactionType) {
             mInteractionType = interactionType;
             mDirty = true;
         }
     }
 
+    /**
+     * Returns true if new data has been supplied since the last time this class has been accessed.
+     */
     public boolean isDirty() {
         return mDirty;
     }
 
-    final int getInteractionType() {
+    /** Return the interaction type that is being compared against for falsing. */
+    public  final int getInteractionType() {
         return mInteractionType;
     }
 
-    MotionEvent getFirstActualMotionEvent() {
-        return mFirstActualMotionEvent;
-    }
-
-    MotionEvent getFirstRecentMotionEvent() {
+    /**
+     * Get the first recorded {@link MotionEvent} of the most recent gesture.
+     *
+     * Note that MotionEvents are not kept forever. As a gesture gets longer in duration, older
+     * MotionEvents may expire and be ejected.
+     */
+    public MotionEvent getFirstRecentMotionEvent() {
         recalculateData();
         return mFirstRecentMotionEvent;
     }
 
-    MotionEvent getLastMotionEvent() {
+    /** Get the last recorded {@link MotionEvent}. */
+    public MotionEvent getLastMotionEvent() {
         recalculateData();
         return mLastMotionEvent;
     }
@@ -171,12 +179,13 @@
      *
      * The angle will be in radians, always be between 0 and 2*PI, inclusive.
      */
-    float getAngle() {
+    public float getAngle() {
         recalculateData();
         return mAngle;
     }
 
-    boolean isHorizontal() {
+    /** Returns if the most recent gesture is more horizontal than vertical. */
+    public boolean isHorizontal() {
         recalculateData();
         if (mRecentMotionEvents.isEmpty()) {
             return false;
@@ -186,7 +195,13 @@
                 .abs(mFirstRecentMotionEvent.getY() - mLastMotionEvent.getY());
     }
 
-    boolean isRight() {
+    /**
+     * Is the most recent gesture more right than left.
+     *
+     * This does not mean the gesture is mostly horizontal. Simply that it ended at least one pixel
+     * to the right of where it started. See also {@link #isHorizontal()}.
+     */
+    public boolean isRight() {
         recalculateData();
         if (mRecentMotionEvents.isEmpty()) {
             return false;
@@ -195,11 +210,18 @@
         return mLastMotionEvent.getX() > mFirstRecentMotionEvent.getX();
     }
 
-    boolean isVertical() {
+    /** Returns if the most recent gesture is more vertical than horizontal. */
+    public boolean isVertical() {
         return !isHorizontal();
     }
 
-    boolean isUp() {
+    /**
+     * Is the most recent gesture more up than down.
+     *
+     * This does not mean the gesture is mostly vertical. Simply that it ended at least one pixel
+     * higher than it started. See also {@link #isVertical()}.
+     */
+    public boolean isUp() {
         recalculateData();
         if (mRecentMotionEvents.isEmpty()) {
             return false;
@@ -209,7 +231,7 @@
     }
 
     /** Returns true if phone is being charged without a cable. */
-    boolean isWirelessCharging() {
+    public boolean isWirelessCharging() {
         return mBatteryController.isWirelessCharging();
     }
 
@@ -292,9 +314,21 @@
         return motionEvents;
     }
 
-    void onSessionEnd() {
-        mFirstActualMotionEvent = null;
+    /** Register a {@link SessionListener}. */
+    public void addSessionListener(SessionListener listener) {
+        mSessionListeners.add(listener);
+    }
 
+    /** Unregister a {@link SessionListener}. */
+    public void removeSessionListener(SessionListener listener) {
+        mSessionListeners.remove(listener);
+    }
+
+    void onSessionStarted() {
+        mSessionListeners.forEach(SessionListener::onSessionStarted);
+    }
+
+    void onSessionEnd() {
         for (MotionEvent ev : mRecentMotionEvents) {
             ev.recycle();
         }
@@ -302,5 +336,24 @@
         mRecentMotionEvents.clear();
 
         mDirty = true;
+
+        mSessionListeners.forEach(SessionListener::onSessionEnded);
+    }
+
+    public boolean isJustUnlockedWithFace() {
+        return mJustUnlockedWithFace;
+    }
+
+    public void setJustUnlockedWithFace(boolean justUnlockedWithFace) {
+        mJustUnlockedWithFace = justUnlockedWithFace;
+    }
+
+    /** Implement to be alerted abotu the beginning and ending of falsing tracking. */
+    public interface SessionListener {
+        /** Called when the lock screen is shown and falsing-tracking begins. */
+        void onSessionStarted();
+
+        /** Called when the lock screen exits and falsing-tracking ends. */
+        void onSessionEnded();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index 1214843..32d27bc 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -21,6 +21,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.util.sensors.ThresholdSensor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -43,21 +44,6 @@
 
     }
 
-    @Override
-    public void onNotificationActive() {
-
-    }
-
-    @Override
-    public void setShowingAod(boolean showingAod) {
-
-    }
-
-    @Override
-    public void onNotificatonStartDraggingDown() {
-
-    }
-
     @VisibleForTesting
     public void setIsUnlockingDisabled(boolean isUnlockingDisabled) {
         mIsUnlockingDisabled = isUnlockingDisabled;
@@ -100,16 +86,6 @@
         return mIsFalseDoubleTap;
     }
 
-    @Override
-    public void onNotificatonStopDraggingDown() {
-
-    }
-
-    @Override
-    public void setNotificationExpanded() {
-
-    }
-
     @VisibleForTesting
     public void setIsClassiferEnabled(boolean isClassiferEnabled) {
         mIsClassiferEnabled = isClassiferEnabled;
@@ -121,76 +97,15 @@
     }
 
     @Override
-    public void onQsDown() {
-
-    }
-
-    @Override
-    public void setQsExpanded(boolean expanded) {
-
-    }
-
-    @VisibleForTesting
-    public void setShouldEnforceBouncer(boolean shouldEnforceBouncer) {
-        mShouldEnforceBouncer = shouldEnforceBouncer;
-    }
-
-    @Override
     public boolean shouldEnforceBouncer() {
         return mShouldEnforceBouncer;
     }
 
     @Override
-    public void onTrackingStarted(boolean secure) {
-
-    }
-
-    @Override
-    public void onTrackingStopped() {
-
-    }
-
-    @Override
-    public void onLeftAffordanceOn() {
-
-    }
-
-    @Override
-    public void onCameraOn() {
-
-    }
-
-    @Override
-    public void onAffordanceSwipingStarted(boolean rightCorner) {
-
-    }
-
-    @Override
-    public void onAffordanceSwipingAborted() {
-
-    }
-
-    @Override
-    public void onStartExpandingFromPulse() {
-
-    }
-
-    @Override
-    public void onExpansionFromPulseStopped() {
-
-    }
-
-    @Override
     public Uri reportRejectedTouch() {
         return null;
     }
 
-    @Override
-    public void onScreenOnFromTouch() {
-
-    }
-
-
     @VisibleForTesting
     public void setIsReportingEnabled(boolean isReportingEnabled) {
         mIsReportingEnabled = isReportingEnabled;
@@ -202,61 +117,6 @@
     }
 
     @Override
-    public void onUnlockHintStarted() {
-
-    }
-
-    @Override
-    public void onCameraHintStarted() {
-
-    }
-
-    @Override
-    public void onLeftAffordanceHintStarted() {
-
-    }
-
-    @Override
-    public void onScreenTurningOn() {
-
-    }
-
-    @Override
-    public void onScreenOff() {
-
-    }
-
-    @Override
-    public void onNotificationStopDismissing() {
-
-    }
-
-    @Override
-    public void onNotificationDismissed() {
-
-    }
-
-    @Override
-    public void onNotificationStartDismissing() {
-
-    }
-
-    @Override
-    public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
-
-    }
-
-    @Override
-    public void onBouncerShown() {
-
-    }
-
-    @Override
-    public void onBouncerHidden() {
-
-    }
-
-    @Override
     public void onTouchEvent(MotionEvent ev, int width, int height) {
 
     }
@@ -268,4 +128,9 @@
     @Override
     public void cleanup() {
     }
+
+    @Override
+    public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 814fff9..7462941 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -17,37 +17,30 @@
 package com.android.systemui.classifier;
 
 import android.content.Context;
-import android.content.res.Resources;
-import android.hardware.SensorManager;
 import android.net.Uri;
 import android.provider.DeviceConfig;
 import android.view.MotionEvent;
-import android.view.ViewConfiguration;
 
 import androidx.annotation.NonNull;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dumpable;
 import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
-import com.android.systemui.classifier.brightline.FalsingDataProvider;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dock.DockManager;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.FalsingPlugin;
 import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.ProximitySensor;
+import com.android.systemui.util.sensors.ThresholdSensor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
+import javax.inject.Provider;
 
 /**
  * Simple passthrough implementation of {@link FalsingManager} allowing plugins to swap in.
@@ -57,21 +50,14 @@
 @SysUISingleton
 public class FalsingManagerProxy implements FalsingManager, Dumpable {
 
-    private static final String PROXIMITY_SENSOR_TAG = "FalsingManager";
     private static final String DUMPABLE_TAG = "FalsingManager";
     public static final String FALSING_REMAIN_LOCKED = "falsing_failure_after_attempts";
     public static final String FALSING_SUCCESS = "falsing_success_after_attempts";
 
     private final PluginManager mPluginManager;
-    private final ProximitySensor mProximitySensor;
-    private final Resources mResources;
-    private final ViewConfiguration mViewConfiguration;
-    private final FalsingDataProvider mFalsingDataProvider;
     private final DeviceConfigProxy mDeviceConfig;
-    private final DockManager mDockManager;
-    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final Provider<BrightLineFalsingManager> mBrightLineFalsingManagerProvider;
     private final DumpManager mDumpManager;
-    private final StatusBarStateController mStatusBarStateController;
     final PluginListener<FalsingPlugin> mPluginListener;
 
     private FalsingManager mInternalFalsingManager;
@@ -81,31 +67,15 @@
 
     @Inject
     FalsingManagerProxy(PluginManager pluginManager, @Main Executor executor,
-            ProximitySensor proximitySensor,
-            DeviceConfigProxy deviceConfig, DockManager dockManager,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            DumpManager dumpManager,
-            StatusBarStateController statusBarStateController,
-            @Main Resources resources,
-            ViewConfiguration viewConfiguration,
-            FalsingDataProvider falsingDataProvider) {
+            DeviceConfigProxy deviceConfig, DumpManager dumpManager,
+            Provider<BrightLineFalsingManager> brightLineFalsingManagerProvider) {
         mPluginManager = pluginManager;
-        mProximitySensor = proximitySensor;
-        mDockManager = dockManager;
-        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDumpManager = dumpManager;
-        mStatusBarStateController = statusBarStateController;
-        mResources = resources;
-        mViewConfiguration = viewConfiguration;
-        mFalsingDataProvider = falsingDataProvider;
-        mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
-        mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME);
         mDeviceConfig = deviceConfig;
+        mBrightLineFalsingManagerProvider = brightLineFalsingManagerProvider;
         setupFalsingManager();
         mDeviceConfig.addOnPropertiesChangedListener(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                executor,
-                mDeviceConfigListener
+                DeviceConfig.NAMESPACE_SYSTEMUI, executor, mDeviceConfigListener
         );
 
         mPluginListener = new PluginListener<FalsingPlugin>() {
@@ -144,24 +114,7 @@
         if (mInternalFalsingManager != null) {
             mInternalFalsingManager.cleanup();
         }
-        mInternalFalsingManager = new BrightLineFalsingManager(
-                mFalsingDataProvider,
-                mKeyguardUpdateMonitor,
-                mProximitySensor,
-                mDeviceConfig,
-                mResources,
-                mViewConfiguration,
-                mDockManager,
-                mStatusBarStateController
-        );
-    }
-
-    /**
-     * Returns the FalsingManager implementation in use.
-     */
-    @VisibleForTesting
-    FalsingManager getInternalFalsingManager() {
-        return mInternalFalsingManager;
+        mInternalFalsingManager = mBrightLineFalsingManagerProvider.get();
     }
 
     @Override
@@ -170,21 +123,6 @@
     }
 
     @Override
-    public void onNotificationActive() {
-        mInternalFalsingManager.onNotificationActive();
-    }
-
-    @Override
-    public void setShowingAod(boolean showingAod) {
-        mInternalFalsingManager.setShowingAod(showingAod);
-    }
-
-    @Override
-    public void onNotificatonStartDraggingDown() {
-        mInternalFalsingManager.onNotificatonStartDraggingDown();
-    }
-
-    @Override
     public boolean isUnlockingDisabled() {
         return mInternalFalsingManager.isUnlockingDisabled();
     }
@@ -194,7 +132,6 @@
         return mInternalFalsingManager.isFalseTouch(interactionType);
     }
 
-
     @Override
     public boolean isFalseTap(boolean robustCheck) {
         return mInternalFalsingManager.isFalseTap(robustCheck);
@@ -206,151 +143,36 @@
     }
 
     @Override
-    public void onNotificatonStopDraggingDown() {
-        mInternalFalsingManager.onNotificatonStartDraggingDown();
-    }
-
-    @Override
-    public void setNotificationExpanded() {
-        mInternalFalsingManager.setNotificationExpanded();
-    }
-
-    @Override
     public boolean isClassifierEnabled() {
         return mInternalFalsingManager.isClassifierEnabled();
     }
 
     @Override
-    public void onQsDown() {
-        mInternalFalsingManager.onQsDown();
-    }
-
-    @Override
-    public void setQsExpanded(boolean expanded) {
-        mInternalFalsingManager.setQsExpanded(expanded);
-    }
-
-    @Override
     public boolean shouldEnforceBouncer() {
         return mInternalFalsingManager.shouldEnforceBouncer();
     }
 
     @Override
-    public void onTrackingStarted(boolean secure) {
-        mInternalFalsingManager.onTrackingStarted(secure);
-    }
-
-    @Override
-    public void onTrackingStopped() {
-        mInternalFalsingManager.onTrackingStopped();
-    }
-
-    @Override
-    public void onLeftAffordanceOn() {
-        mInternalFalsingManager.onLeftAffordanceOn();
-    }
-
-    @Override
-    public void onCameraOn() {
-        mInternalFalsingManager.onCameraOn();
-    }
-
-    @Override
-    public void onAffordanceSwipingStarted(boolean rightCorner) {
-        mInternalFalsingManager.onAffordanceSwipingStarted(rightCorner);
-    }
-
-    @Override
-    public void onAffordanceSwipingAborted() {
-        mInternalFalsingManager.onAffordanceSwipingAborted();
-    }
-
-    @Override
-    public void onStartExpandingFromPulse() {
-        mInternalFalsingManager.onStartExpandingFromPulse();
-    }
-
-    @Override
-    public void onExpansionFromPulseStopped() {
-        mInternalFalsingManager.onExpansionFromPulseStopped();
-    }
-
-    @Override
     public Uri reportRejectedTouch() {
         return mInternalFalsingManager.reportRejectedTouch();
     }
 
     @Override
-    public void onScreenOnFromTouch() {
-        mInternalFalsingManager.onScreenOnFromTouch();
-    }
-
-    @Override
     public boolean isReportingEnabled() {
         return mInternalFalsingManager.isReportingEnabled();
     }
 
     @Override
-    public void onUnlockHintStarted() {
-        mInternalFalsingManager.onUnlockHintStarted();
-    }
-
-    @Override
-    public void onCameraHintStarted() {
-        mInternalFalsingManager.onCameraHintStarted();
-    }
-
-    @Override
-    public void onLeftAffordanceHintStarted() {
-        mInternalFalsingManager.onLeftAffordanceHintStarted();
-    }
-
-    @Override
-    public void onScreenTurningOn() {
-        mInternalFalsingManager.onScreenTurningOn();
-    }
-
-    @Override
-    public void onScreenOff() {
-        mInternalFalsingManager.onScreenOff();
-    }
-
-    @Override
-    public void onNotificationStopDismissing() {
-        mInternalFalsingManager.onNotificationStopDismissing();
-    }
-
-    @Override
-    public void onNotificationDismissed() {
-        mInternalFalsingManager.onNotificationDismissed();
-    }
-
-    @Override
-    public void onNotificationStartDismissing() {
-        mInternalFalsingManager.onNotificationStartDismissing();
-    }
-
-    @Override
-    public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
-        mInternalFalsingManager.onNotificationDoubleTap(accepted, dx, dy);
-    }
-
-    @Override
-    public void onBouncerShown() {
-        mInternalFalsingManager.onBouncerShown();
-    }
-
-    @Override
-    public void onBouncerHidden() {
-        mInternalFalsingManager.onBouncerHidden();
-    }
-
-    @Override
     public void onTouchEvent(MotionEvent ev, int width, int height) {
         mInternalFalsingManager.onTouchEvent(ev, width, height);
     }
 
     @Override
+    public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+        mInternalFalsingManager.onProximityEvent(proximityEvent);
+    }
+
+    @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         mInternalFalsingManager.dump(fd, pw, args);
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
similarity index 64%
copy from tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
copy to packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
index 6bc9dcb..937bcba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
@@ -14,6 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+package com.android.systemui.classifier;
 
-internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
+import com.android.systemui.dagger.SysUISingleton;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Dagger Module for Falsing. */
+@Module
+public interface FalsingModule {
+    /** */
+    @Binds
+    @SysUISingleton
+    FalsingCollector bindsFalsingCollector(FalsingCollectorImpl impl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 334102d..70a57cc 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -16,12 +16,10 @@
 
 package com.android.systemui.classifier.brightline;
 
-import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_REMAIN_LOCKED;
 import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS;
 
 import android.app.ActivityManager;
 import android.content.res.Resources;
-import android.hardware.biometrics.BiometricSourceType;
 import android.net.Uri;
 import android.os.Build;
 import android.util.IndentingPrintWriter;
@@ -32,18 +30,15 @@
 import androidx.annotation.NonNull;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
 import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.FalsingDataProvider;
+import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.NotificationTapHelper;
 import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.ProximitySensor;
 import com.android.systemui.util.sensors.ThresholdSensor;
 
 import java.io.FileDescriptor;
@@ -56,30 +51,25 @@
 import java.util.StringJoiner;
 import java.util.stream.Collectors;
 
+import javax.inject.Inject;
+
 /**
  * FalsingManager designed to make clear why a touch was rejected.
  */
 public class BrightLineFalsingManager implements FalsingManager {
 
     private static final String TAG = "FalsingManager";
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int RECENT_INFO_LOG_SIZE = 40;
     private static final int RECENT_SWIPE_LOG_SIZE = 20;
 
     private final FalsingDataProvider mDataProvider;
-    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    private final ProximitySensor mProximitySensor;
     private final DockManager mDockManager;
-    private final StatusBarStateController mStatusBarStateController;
     private final SingleTapClassifier mSingleTapClassifier;
     private final DoubleTapClassifier mDoubleTapClassifier;
-    private boolean mSessionStarted;
-    private MetricsLogger mMetricsLogger;
+    private final MetricsLogger mMetricsLogger;
     private int mIsFalseTouchCalls;
-    private boolean mShowingAod;
-    private boolean mScreenOn;
-    private boolean mJustUnlockedWithFace;
     private static final Queue<String> RECENT_INFO_LOG =
             new ArrayDeque<>(RECENT_INFO_LOG_SIZE + 1);
     private static final Queue<DebugSwipeRecord> RECENT_SWIPES =
@@ -87,46 +77,26 @@
 
     private final List<FalsingClassifier> mClassifiers;
 
-    private ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent;
-
-    private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
-            new KeyguardUpdateMonitorCallback() {
-                @Override
-                public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType,
-                        boolean isStrongBiometric) {
-                    if (userId == KeyguardUpdateMonitor.getCurrentUser()
-                            && biometricSourceType == BiometricSourceType.FACE) {
-                        mJustUnlockedWithFace = true;
-                    }
-                }
-            };
-    private boolean mPreviousResult = false;
-
-    private StatusBarStateController.StateListener mStatusBarStateListener =
-            new StatusBarStateController.StateListener() {
+    private final SessionListener mSessionListener = new SessionListener() {
         @Override
-        public void onStateChanged(int newState) {
-            logDebug("StatusBarState=" + StatusBarState.toShortString(newState));
-            mState = newState;
-            updateSessionActive();
+        public void onSessionEnded() {
+            mClassifiers.forEach(FalsingClassifier::onSessionEnded);
+        }
+
+        @Override
+        public void onSessionStarted() {
+            mClassifiers.forEach(FalsingClassifier::onSessionStarted);
         }
     };
-    private int mState;
 
+    private boolean mPreviousResult = false;
+
+    @Inject
     public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
-            KeyguardUpdateMonitor keyguardUpdateMonitor, ProximitySensor proximitySensor,
             DeviceConfigProxy deviceConfigProxy, @Main Resources resources,
-            ViewConfiguration viewConfiguration, DockManager dockManager,
-            StatusBarStateController statusBarStateController) {
-        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+            ViewConfiguration viewConfiguration, DockManager dockManager) {
         mDataProvider = falsingDataProvider;
-        mProximitySensor = proximitySensor;
         mDockManager = dockManager;
-        mStatusBarStateController = statusBarStateController;
-        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
-        mStatusBarStateController.addCallback(mStatusBarStateListener);
-        mState = mStatusBarStateController.getState();
 
         mMetricsLogger = new MetricsLogger();
         mClassifiers = new ArrayList<>();
@@ -146,58 +116,8 @@
         mDoubleTapClassifier = new DoubleTapClassifier(mDataProvider, mSingleTapClassifier,
                 resources.getDimension(R.dimen.double_tap_slop),
                 NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS);
-    }
 
-    private void registerSensors() {
-        if (!mDataProvider.isWirelessCharging()) {
-            mProximitySensor.register(mSensorEventListener);
-        }
-    }
-
-    private void unregisterSensors() {
-        mProximitySensor.unregister(mSensorEventListener);
-    }
-
-    private void sessionStart() {
-        if (!mSessionStarted && shouldSessionBeActive()) {
-            logDebug("Starting Session");
-            mSessionStarted = true;
-            mJustUnlockedWithFace = false;
-            registerSensors();
-            mClassifiers.forEach(FalsingClassifier::onSessionStarted);
-        }
-    }
-
-    private void sessionEnd() {
-        if (mSessionStarted) {
-            logDebug("Ending Session");
-            mSessionStarted = false;
-            unregisterSensors();
-            mDataProvider.onSessionEnd();
-            mClassifiers.forEach(FalsingClassifier::onSessionEnded);
-            if (mIsFalseTouchCalls != 0) {
-                mMetricsLogger.histogram(FALSING_REMAIN_LOCKED, mIsFalseTouchCalls);
-                mIsFalseTouchCalls = 0;
-            }
-        }
-    }
-
-
-    private void updateSessionActive() {
-        if (shouldSessionBeActive()) {
-            sessionStart();
-        } else {
-            sessionEnd();
-        }
-    }
-
-    private boolean shouldSessionBeActive() {
-        return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
-    }
-
-    private void updateInteractionType(@Classifier.InteractionType int type) {
-        logDebug("InteractionType: " + type);
-        mDataProvider.setInteractionType(type);
+        mDataProvider.addSessionListener(mSessionListener);
     }
 
     @Override
@@ -212,8 +132,9 @@
             return mPreviousResult;
         }
 
-        mPreviousResult = !ActivityManager.isRunningInUserTestHarness() && !mJustUnlockedWithFace
-                && !mDockManager.isDocked() && mClassifiers.stream().anyMatch(falsingClassifier -> {
+        mPreviousResult = !ActivityManager.isRunningInUserTestHarness()
+                && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()
+                && mClassifiers.stream().anyMatch(falsingClassifier -> {
                     boolean result = falsingClassifier.isFalseTouch();
                     if (result) {
                         logInfo(String.format(
@@ -245,9 +166,8 @@
                                     (int) (motionEvent.getEventTime() - motionEvent.getDownTime())))
                             .collect(Collectors.toList())));
             while (RECENT_SWIPES.size() > RECENT_INFO_LOG_SIZE) {
-                DebugSwipeRecord record = RECENT_SWIPES.remove();
+                RECENT_SWIPES.remove();
             }
-
         }
 
         return mPreviousResult;
@@ -265,8 +185,12 @@
             return true;
         }
 
-        // TODO(b/172655679): we always reject single-taps when doing a robust check for now.
-        return robustCheck;
+        // TODO(b/172655679): More heuristics to come. For now, allow touches through if face-authed
+        if (robustCheck) {
+            return !mDataProvider.isJustUnlockedWithFace();
+        }
+
+        return false;
     }
 
     @Override
@@ -287,11 +211,11 @@
     public void onTouchEvent(MotionEvent motionEvent, int width, int height) {
         // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
         // make these calls.
-        mDataProvider.onMotionEvent(motionEvent);
         mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent));
     }
 
-    private void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
+    @Override
+    public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
         // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
         // make these calls.
         mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent));
@@ -303,22 +227,6 @@
             mMetricsLogger.histogram(FALSING_SUCCESS, mIsFalseTouchCalls);
             mIsFalseTouchCalls = 0;
         }
-        sessionEnd();
-    }
-
-    @Override
-    public void onNotificationActive() {
-    }
-
-    @Override
-    public void setShowingAod(boolean showingAod) {
-        mShowingAod = showingAod;
-        updateSessionActive();
-    }
-
-    @Override
-    public void onNotificatonStartDraggingDown() {
-        updateInteractionType(Classifier.NOTIFICATION_DRAG_DOWN);
     }
 
     @Override
@@ -326,147 +234,29 @@
         return false;
     }
 
-
-    @Override
-    public void onNotificatonStopDraggingDown() {
-    }
-
-    @Override
-    public void setNotificationExpanded() {
-    }
-
-    @Override
-    public void onQsDown() {
-        updateInteractionType(Classifier.QUICK_SETTINGS);
-    }
-
-    @Override
-    public void setQsExpanded(boolean expanded) {
-        if (expanded) {
-            unregisterSensors();
-        } else if (mSessionStarted) {
-            registerSensors();
-        }
-    }
-
     @Override
     public boolean shouldEnforceBouncer() {
         return false;
     }
 
     @Override
-    public void onTrackingStarted(boolean secure) {
-        updateInteractionType(secure ? Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
-    }
-
-    @Override
-    public void onTrackingStopped() {
-    }
-
-    @Override
-    public void onLeftAffordanceOn() {
-    }
-
-    @Override
-    public void onCameraOn() {
-    }
-
-    @Override
-    public void onAffordanceSwipingStarted(boolean rightCorner) {
-        updateInteractionType(
-                rightCorner ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE);
-    }
-
-    @Override
-    public void onAffordanceSwipingAborted() {
-    }
-
-    @Override
-    public void onStartExpandingFromPulse() {
-        updateInteractionType(Classifier.PULSE_EXPAND);
-    }
-
-    @Override
-    public void onExpansionFromPulseStopped() {
-    }
-
-    @Override
     public Uri reportRejectedTouch() {
         return null;
     }
 
     @Override
-    public void onScreenOnFromTouch() {
-        onScreenTurningOn();
-    }
-
-    @Override
     public boolean isReportingEnabled() {
         return false;
     }
 
     @Override
-    public void onUnlockHintStarted() {
-    }
-
-    @Override
-    public void onCameraHintStarted() {
-    }
-
-    @Override
-    public void onLeftAffordanceHintStarted() {
-    }
-
-    @Override
-    public void onScreenTurningOn() {
-        mScreenOn = true;
-        updateSessionActive();
-    }
-
-    @Override
-    public void onScreenOff() {
-        mScreenOn = false;
-        updateSessionActive();
-    }
-
-
-    @Override
-    public void onNotificationStopDismissing() {
-    }
-
-    @Override
-    public void onNotificationDismissed() {
-    }
-
-    @Override
-    public void onNotificationStartDismissing() {
-        updateInteractionType(Classifier.NOTIFICATION_DISMISS);
-    }
-
-    @Override
-    public void onNotificationDoubleTap(boolean b, float v, float v1) {
-    }
-
-    @Override
-    public void onBouncerShown() {
-        unregisterSensors();
-    }
-
-    @Override
-    public void onBouncerHidden() {
-        if (mSessionStarted) {
-            registerSensors();
-        }
-    }
-
-    @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
         ipw.println("BRIGHTLINE FALSING MANAGER");
         ipw.print("classifierEnabled=");
         ipw.println(isClassifierEnabled() ? 1 : 0);
         ipw.print("mJustUnlockedWithFace=");
-        ipw.println(mJustUnlockedWithFace ? 1 : 0);
+        ipw.println(mDataProvider.isJustUnlockedWithFace() ? 1 : 0);
         ipw.print("isDocked=");
         ipw.println(mDockManager.isDocked() ? 1 : 0);
         ipw.print("width=");
@@ -496,9 +286,7 @@
 
     @Override
     public void cleanup() {
-        unregisterSensors();
-        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
-        mStatusBarStateController.removeCallback(mStatusBarStateListener);
+        mDataProvider.removeSessionListener(mSessionListener);
     }
 
     static void logDebug(String msg) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
index 520e0a1..a73ccf5 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
@@ -23,6 +23,7 @@
 
 import android.provider.DeviceConfig;
 
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.DeviceConfigProxy;
 
 import java.util.Locale;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
index 0329183..524d524 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
@@ -27,6 +27,7 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.DeviceConfigProxy;
 
 import java.util.List;
@@ -112,7 +113,6 @@
 
     private DistanceVectors calculateDistances() {
         // This code assumes that there will be no missed DOWN or UP events.
-        VelocityTracker velocityTracker = VelocityTracker.obtain();
         List<MotionEvent> motionEvents = getRecentMotionEvents();
 
         if (motionEvents.size() < 3) {
@@ -120,6 +120,8 @@
             return new DistanceVectors(0, 0, 0, 0);
         }
 
+        VelocityTracker velocityTracker = VelocityTracker.obtain();
+
         for (MotionEvent motionEvent : motionEvents) {
             velocityTracker.addMovement(motionEvent);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
index d3af1c3..a27ea61 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
@@ -18,6 +18,8 @@
 
 import android.view.MotionEvent;
 
+import com.android.systemui.classifier.FalsingDataProvider;
+
 import java.util.List;
 import java.util.Queue;
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
index ed417b3..568dc43 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
@@ -19,6 +19,7 @@
 import android.view.MotionEvent;
 
 import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.sensors.ProximitySensor;
 
 import java.util.List;
@@ -27,7 +28,7 @@
 /**
  * Base class for rules that determine False touches.
  */
-abstract class FalsingClassifier {
+public abstract class FalsingClassifier {
     private final FalsingDataProvider mDataProvider;
 
     FalsingClassifier(FalsingDataProvider dataProvider) {
@@ -126,15 +127,18 @@
      */
     abstract String getReason();
 
-    static void logDebug(String msg) {
+    /** */
+    public static void logDebug(String msg) {
         BrightLineFalsingManager.logDebug(msg);
     }
 
-    static void logInfo(String msg) {
+    /** */
+    public static void logInfo(String msg) {
         BrightLineFalsingManager.logInfo(msg);
     }
 
-    static void logError(String msg) {
+    /** */
+    public static void logError(String msg) {
         BrightLineFalsingManager.logError(msg);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
index b726c3e..dd5d8a8 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
@@ -21,6 +21,8 @@
 
 import android.view.MotionEvent;
 
+import com.android.systemui.classifier.FalsingDataProvider;
+
 import java.util.Locale;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
index b128678..3551c24 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
@@ -22,6 +22,7 @@
 import android.provider.DeviceConfig;
 import android.view.MotionEvent;
 
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.sensors.ProximitySensor;
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
index 47708f4..8c76481 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
@@ -18,6 +18,8 @@
 
 import android.view.MotionEvent;
 
+import com.android.systemui.classifier.FalsingDataProvider;
+
 import java.util.List;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
index 92aa7c5..7430a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
@@ -36,7 +36,7 @@
     private final LinkedList<MotionEvent> mMotionEvents;
     private final long mMaxAgeMs;
 
-    TimeLimitedMotionEventBuffer(long maxAgeMs) {
+    public TimeLimitedMotionEventBuffer(long maxAgeMs) {
         super();
         mMaxAgeMs = maxAgeMs;
         mMotionEvents = new LinkedList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
index 5f1b37a..f62871f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
@@ -26,6 +26,8 @@
 import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
 import static com.android.systemui.classifier.Classifier.UNLOCK;
 
+import com.android.systemui.classifier.FalsingDataProvider;
+
 /**
  * Ensure that the swipe direction generally matches that of the interaction type.
  */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
index a796f3c..9ca77d3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
@@ -25,6 +25,7 @@
 import android.provider.DeviceConfig;
 import android.view.MotionEvent;
 
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.DeviceConfigProxy;
 
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 13ff3f5..ec4a91c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -22,6 +22,7 @@
 import com.android.systemui.keyguard.WorkLockActivity;
 import com.android.systemui.screenrecord.ScreenRecordDialog;
 import com.android.systemui.settings.brightness.BrightnessDialog;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
 import com.android.systemui.tuner.TunerActivity;
 import com.android.systemui.usb.UsbDebuggingActivity;
 import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
@@ -85,4 +86,10 @@
     @IntoMap
     @ClassKey(CreateUserActivity.class)
     public abstract Activity bindCreateUserActivity(CreateUserActivity activity);
+
+    /** Inject into TvNotificationPanelActivity. */
+    @Binds
+    @IntoMap
+    @ClassKey(TvNotificationPanelActivity.class)
+    public abstract Activity bindTvNotificationPanelActivity(TvNotificationPanelActivity activity);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index c3f2e18..2c06c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -151,6 +151,12 @@
 
     @Provides
     @Singleton
+    static ActivityTaskManager provideActivityTaskManager() {
+        return ActivityTaskManager.getInstance();
+    }
+
+    @Provides
+    @Singleton
     static IActivityTaskManager provideIActivityTaskManager() {
         return ActivityTaskManager.getService();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index c0013d8..9f6c19b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -34,8 +34,8 @@
 import com.android.systemui.statusbar.dagger.StatusBarModule;
 import com.android.systemui.statusbar.notification.InstantAppNotifier;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.tv.TvNotificationPanel;
 import com.android.systemui.statusbar.tv.TvStatusBar;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationPanel;
 import com.android.systemui.theme.ThemeOverlayController;
 import com.android.systemui.toast.ToastUI;
 import com.android.systemui.util.leak.GarbageMonitor;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 780bb5b..4d69700 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -27,6 +27,7 @@
 import com.android.systemui.BootCompleteCacheImpl;
 import com.android.systemui.appops.dagger.AppOpsModule;
 import com.android.systemui.assist.AssistModule;
+import com.android.systemui.classifier.FalsingModule;
 import com.android.systemui.controls.dagger.ControlsModule;
 import com.android.systemui.demomode.dagger.DemoModeModule;
 import com.android.systemui.doze.dagger.DozeComponent;
@@ -89,6 +90,7 @@
             AssistModule.class,
             ControlsModule.class,
             DemoModeModule.class,
+            FalsingModule.class,
             LogModule.class,
             PeopleHubModule.class,
             PowerModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
index 94b8ba3..ef696a8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
@@ -16,8 +16,8 @@
 
 package com.android.systemui.doze;
 
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.doze.dagger.DozeScope;
-import com.android.systemui.plugins.FalsingManager;
 
 import javax.inject.Inject;
 
@@ -27,16 +27,16 @@
 @DozeScope
 public class DozeFalsingManagerAdapter implements DozeMachine.Part {
 
-    private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
 
     @Inject
-    public DozeFalsingManagerAdapter(FalsingManager falsingManager) {
-        mFalsingManager = falsingManager;
+    public DozeFalsingManagerAdapter(FalsingCollector falsingCollector) {
+        mFalsingCollector = falsingCollector;
     }
 
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
-        mFalsingManager.setShowingAod(isAodMode(newState));
+        mFalsingCollector.setShowingAod(isAodMode(newState));
     }
 
     private boolean isAodMode(DozeMachine.State state) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
index d1e5059..73abf45 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
@@ -21,6 +21,7 @@
 private const val MILLIS_PER_MINUTES = 1000 * 60f
 private const val BURN_IN_PREVENTION_PERIOD_Y = 521f
 private const val BURN_IN_PREVENTION_PERIOD_X = 83f
+private const val BURN_IN_PREVENTION_PERIOD_SCALE = 180f
 
 /**
  * Returns the translation offset that should be used to avoid burn in at
@@ -36,6 +37,14 @@
 }
 
 /**
+ * Returns a value to scale a view in order to avoid burn in.
+ */
+fun getBurnInScale(): Float {
+    return 0.8f + zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
+            0.2f, BURN_IN_PREVENTION_PERIOD_SCALE)
+}
+
+/**
  * Implements a continuous, piecewise linear, periodic zig-zag function
  *
  * Can be thought of as a linear approximation of abs(sin(x)))
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index aea0dd0..c6bfcba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -88,12 +88,12 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardService;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
 import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -223,7 +223,7 @@
     private boolean mBootSendUserPresent;
     private boolean mShuttingDown;
     private boolean mDozing;
-    private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
 
     /** High level access to the power manager for WakeLocks */
     private final PowerManager mPM;
@@ -715,7 +715,7 @@
      */
     public KeyguardViewMediator(
             Context context,
-            FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             LockPatternUtils lockPatternUtils,
             BroadcastDispatcher broadcastDispatcher,
             Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy,
@@ -727,7 +727,7 @@
             NavigationModeController navigationModeController,
             KeyguardDisplayManager keyguardDisplayManager) {
         super(context);
-        mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
         mLockPatternUtils = lockPatternUtils;
         mBroadcastDispatcher = broadcastDispatcher;
         mKeyguardViewControllerLazy = statusBarKeyguardViewManagerLazy;
@@ -1682,7 +1682,7 @@
                             "KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
                     StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
                     handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration);
-                    mFalsingManager.onSuccessfulUnlock();
+                    mFalsingCollector.onSuccessfulUnlock();
                     Trace.endSection();
                     break;
                 case KEYGUARD_DONE_PENDING_TIMEOUT:
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index e50fd6a..d7b5eea 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -31,6 +31,8 @@
 import com.android.keyguard.KeyguardViewController;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.classifier.FalsingModule;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -39,7 +41,6 @@
 import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
@@ -59,7 +60,8 @@
 /**
  * Dagger Module providing {@link StatusBar}.
  */
-@Module(subcomponents = {KeyguardStatusViewComponent.class})
+@Module(subcomponents = {KeyguardStatusViewComponent.class},
+        includes = {FalsingModule.class})
 public class KeyguardModule {
     /**
      * Provides our instance of KeyguardViewMediator which is considered optional.
@@ -68,7 +70,7 @@
     @SysUISingleton
     public static KeyguardViewMediator newKeyguardViewMediator(
             Context context,
-            FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             LockPatternUtils lockPatternUtils,
             BroadcastDispatcher broadcastDispatcher,
             Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy,
@@ -83,7 +85,7 @@
             KeyguardDisplayManager keyguardDisplayManager) {
         return new KeyguardViewMediator(
                 context,
-                falsingManager,
+                falsingCollector,
                 lockPatternUtils,
                 broadcastDispatcher,
                 statusBarKeyguardViewManagerLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 5eb6687..9353526 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -12,6 +12,7 @@
 import android.widget.LinearLayout
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.R
+import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
@@ -44,6 +45,7 @@
     @Main executor: DelayableExecutor,
     private val mediaManager: MediaDataManager,
     configurationController: ConfigurationController,
+    falsingCollector: FalsingCollector,
     falsingManager: FalsingManager
 ) {
     /**
@@ -156,7 +158,7 @@
         pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
         mediaCarouselScrollHandler = MediaCarouselScrollHandler(mediaCarousel, pageIndicator,
                 executor, mediaManager::onSwipeToDismiss, this::updatePageIndicatorLocation,
-                this::closeGuts, falsingManager)
+                this::closeGuts, falsingCollector, falsingManager)
         isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
         inflateSettingsButton()
         mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index cb14f31..bb6fbfa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.qs.PageIndicator
 import com.android.systemui.R
 import com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS
+import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.plugins.FalsingManager
 import com.android.wm.shell.animation.PhysicsAnimator
 import com.android.systemui.util.concurrency.DelayableExecutor
@@ -58,6 +59,7 @@
     private val dismissCallback: () -> Unit,
     private var translationChangedListener: () -> Unit,
     private val closeGuts: () -> Unit,
+    private val falsingCollector: FalsingCollector,
     private val falsingManager: FalsingManager
 ) {
     /**
@@ -162,7 +164,7 @@
 
         override fun onDown(e: MotionEvent?): Boolean {
             if (falsingProtectionNeeded) {
-                falsingManager.onNotificationStartDismissing()
+                falsingCollector.onNotificationStartDismissing()
             }
             return false
         }
@@ -258,7 +260,7 @@
     private fun onTouch(motionEvent: MotionEvent): Boolean {
         val isUp = motionEvent.action == MotionEvent.ACTION_UP
         if (isUp && falsingProtectionNeeded) {
-            falsingManager.onNotificationStopDismissing()
+            falsingCollector.onNotificationStopDismissing()
         }
         if (gestureDetector.onTouchEvent(motionEvent)) {
             if (isUp) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 3295595..5cd3b33 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -19,10 +19,10 @@
 import android.app.Activity;
 import android.app.INotificationManager;
 import android.app.people.IPeopleManager;
+import android.app.people.PeopleSpaceTile;
 import android.content.Context;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
-import android.content.pm.ShortcutInfo;
 import android.os.Bundle;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -68,13 +68,13 @@
      */
     private void setTileViewsWithPriorityConversations() {
         try {
-            List<Map.Entry<Long, ShortcutInfo>> shortcutInfos = PeopleSpaceUtils.getShortcutInfos(
-                    mContext, mNotificationManager, mPeopleManager);
-            for (Map.Entry<Long, ShortcutInfo> entry : shortcutInfos) {
-                ShortcutInfo shortcutInfo = entry.getValue();
+            List<Map.Entry<Long, PeopleSpaceTile>> tiles = PeopleSpaceUtils.getTiles(
+                    mContext, mNotificationManager, mPeopleManager, mLauncherApps);
+            for (Map.Entry<Long, PeopleSpaceTile> entry : tiles) {
+                PeopleSpaceTile tile = entry.getValue();
                 PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext, mPeopleSpaceLayout,
-                        shortcutInfo.getId());
-                setTileView(tileView, shortcutInfo, entry.getKey());
+                        tile.getId());
+                setTileView(tileView, tile, entry.getKey());
             }
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve conversations", e);
@@ -82,18 +82,18 @@
     }
 
     /** Sets {@code tileView} with the data in {@code conversation}. */
-    private void setTileView(PeopleSpaceTileView tileView, ShortcutInfo shortcutInfo,
+    private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile,
             long lastInteraction) {
         try {
-            String pkg = shortcutInfo.getPackage();
+            String pkg = tile.getPackageName();
             String status =
                     PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
             tileView.setStatus(status);
 
-            tileView.setName(shortcutInfo.getLabel().toString());
+            tileView.setName(tile.getUserName().toString());
             tileView.setPackageIcon(mPackageManager.getApplicationIcon(pkg));
-            tileView.setPersonIcon(mLauncherApps.getShortcutIconDrawable(shortcutInfo, 0));
-            tileView.setOnClickListener(mLauncherApps, shortcutInfo);
+            tileView.setPersonIcon(tile.getUserIcon());
+            tileView.setOnClickListener(mLauncherApps, tile);
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve shortcut information", e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
index d5ef190..4aea5b8 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
@@ -16,10 +16,12 @@
 
 package com.android.systemui.people;
 
+import android.app.people.PeopleSpaceTile;
 import android.content.Context;
 import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -71,13 +73,15 @@
         mPackageIconView.setImageDrawable(drawable);
     }
 
-    /** Sets the person drawable on the tile. */
-    public void setPersonIcon(Drawable drawable) {
-        mPersonIconView.setImageDrawable(drawable);
+    /** Sets the person bitmap on the tile. */
+    public void setPersonIcon(Icon icon) {
+        mPersonIconView.setImageIcon(icon);
     }
 
     /** Sets the click listener of the tile. */
-    public void setOnClickListener(LauncherApps launcherApps, ShortcutInfo shortcutInfo) {
-        mTileView.setOnClickListener(v -> launcherApps.startShortcut(shortcutInfo, null, null));
+    public void setOnClickListener(LauncherApps launcherApps, PeopleSpaceTile tile) {
+        mTileView.setOnClickListener(v ->
+                launcherApps.startShortcut(tile.getPackageName(), tile.getId(), null, null,
+                        UserHandle.getUserHandleForUid(tile.getUid())));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 35e445b..fe262b4 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -19,8 +19,9 @@
 import android.app.INotificationManager;
 import android.app.people.ConversationChannel;
 import android.app.people.IPeopleManager;
+import android.app.people.PeopleSpaceTile;
 import android.content.Context;
-import android.content.pm.ShortcutInfo;
+import android.content.pm.LauncherApps;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
@@ -51,30 +52,34 @@
     private static final int MIN_HOUR = 1;
     private static final int ONE_DAY = 1;
 
-
     /** Returns a list of map entries corresponding to user's conversations. */
-    public static List<Map.Entry<Long, ShortcutInfo>> getShortcutInfos(Context context,
-            INotificationManager notificationManager, IPeopleManager peopleManager)
+    public static List<Map.Entry<Long, PeopleSpaceTile>> getTiles(
+            Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
+            LauncherApps launcherApps)
             throws Exception {
         boolean showAllConversations = Settings.Global.getInt(context.getContentResolver(),
                 Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
         List<ConversationChannelWrapper> conversations = notificationManager.getConversations(
                 true).getList();
-        List<Map.Entry<Long, ShortcutInfo>> shortcutInfos = getSortedShortcutInfos(peopleManager,
-                conversations.stream().map(c -> c.getShortcutInfo()));
+        List<Map.Entry<Long, PeopleSpaceTile>> tiles = getSortedTiles(peopleManager,
+                conversations.stream().map(c ->
+                        new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build()));
         if (showAllConversations) {
             List<ConversationChannel> recentConversations =
                     peopleManager.getRecentConversations().getList();
-            List<Map.Entry<Long, ShortcutInfo>> recentShortcutInfos = getSortedShortcutInfos(
-                    peopleManager, recentConversations.stream().map(c -> c.getShortcutInfo()));
-            shortcutInfos.addAll(recentShortcutInfos);
+            List<Map.Entry<Long, PeopleSpaceTile>> recentTiles =
+                    getSortedTiles(peopleManager, recentConversations.stream().map(c ->
+                            new PeopleSpaceTile
+                                    .Builder(c.getShortcutInfo(), launcherApps)
+                                    .build()));
+            tiles.addAll(recentTiles);
         }
-        return shortcutInfos;
+        return tiles;
     }
 
     /** Returns a list sorted by ascending last interaction time from {@code stream}. */
-    private static List<Map.Entry<Long, ShortcutInfo>> getSortedShortcutInfos(
-            IPeopleManager peopleManager, Stream<ShortcutInfo> stream) {
+    private static List<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
+            IPeopleManager peopleManager, Stream<PeopleSpaceTile> stream) {
         return stream
                 .filter(c -> shouldKeepConversation(c))
                 .map(c -> Map.entry(getLastInteraction(peopleManager, c), c))
@@ -82,13 +87,13 @@
                 .collect(Collectors.toList());
     }
 
-    /** Returns the last interaction time with the user specified by {@code shortcutInfo}. */
+    /** Returns the last interaction time with the user specified by {@code PeopleSpaceTile}. */
     private static Long getLastInteraction(IPeopleManager peopleManager,
-            ShortcutInfo shortcutInfo) {
+            PeopleSpaceTile tile) {
         try {
-            int userId = UserHandle.getUserHandleForUid(shortcutInfo.getUserId()).getIdentifier();
-            String pkg = shortcutInfo.getPackage();
-            return peopleManager.getLastInteraction(pkg, userId, shortcutInfo.getId());
+            int userId = UserHandle.getUserHandleForUid(tile.getUid()).getIdentifier();
+            String pkg = tile.getPackageName();
+            return peopleManager.getLastInteraction(pkg, userId, tile.getId());
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve last interaction time", e);
             return 0L;
@@ -157,13 +162,13 @@
      *
      * <p>A valid {@code conversation} must:
      *     <ul>
-     *         <li>Have a non-null {@link ShortcutInfo}
-     *         <li>Have an associated label in the {@link ShortcutInfo}
+     *         <li>Have a non-null {@link PeopleSpaceTile}
+     *         <li>Have an associated label in the {@link PeopleSpaceTile}
      *     </ul>
      * </li>
      */
-    public static boolean shouldKeepConversation(ShortcutInfo shortcutInfo) {
-        return shortcutInfo != null && shortcutInfo.getLabel().length() != 0;
+    public static boolean shouldKeepConversation(PeopleSpaceTile tile) {
+        return tile != null && tile.getUserName().length() != 0;
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
index 44f173b..0b0308f 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
@@ -19,8 +19,8 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.systemui.people.PeopleSpaceUtils;
@@ -36,18 +36,19 @@
         if (DEBUG) Log.d(TAG, "onCreate called");
 
         Intent intent = getIntent();
-        ShortcutInfo shortcutInfo = (ShortcutInfo) intent.getParcelableExtra(
-                PeopleSpaceWidgetProvider.EXTRA_SHORTCUT_INFO
-        );
-        if (shortcutInfo != null) {
+        String tileId = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID);
+        String packageName = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME);
+        int uid = intent.getIntExtra(PeopleSpaceWidgetProvider.EXTRA_UID, 0);
+
+        if (tileId != null && !tileId.isEmpty()) {
             if (DEBUG) {
-                Log.d(TAG, "Launching conversation with shortcutInfo id " + shortcutInfo.getId());
+                Log.d(TAG, "Launching conversation with shortcutInfo id " + tileId);
             }
             try {
                 LauncherApps launcherApps =
                         getApplicationContext().getSystemService(LauncherApps.class);
                 launcherApps.startShortcut(
-                        shortcutInfo, null, null);
+                        packageName, tileId, null, null, UserHandle.getUserHandleForUid(uid));
             } catch (Exception e) {
                 Log.e(TAG, "Exception starting shortcut:" + e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
index aa98b61..9f84514 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
@@ -32,7 +32,9 @@
     private static final String TAG = "PeopleSpaceWidgetPvd";
     private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
 
-    public static final String EXTRA_SHORTCUT_INFO = "extra_shortcut_info";
+    public static final String EXTRA_TILE_ID = "extra_tile_id";
+    public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
+    public static final String EXTRA_UID = "extra_uid";
 
     /** Called when widget updates. */
     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
index a4527c3..1e6c213 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
@@ -18,11 +18,11 @@
 
 import android.app.INotificationManager;
 import android.app.people.IPeopleManager;
+import android.app.people.PeopleSpaceTile;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
-import android.content.pm.ShortcutInfo;
 import android.os.ServiceManager;
 import android.util.Log;
 import android.widget.RemoteViews;
@@ -45,7 +45,7 @@
     private INotificationManager mNotificationManager;
     private PackageManager mPackageManager;
     private LauncherApps mLauncherApps;
-    private List<Map.Entry<Long, ShortcutInfo>> mShortcutInfos = new ArrayList<>();
+    private List<Map.Entry<Long, PeopleSpaceTile>> mTiles = new ArrayList<>();
     private Context mContext;
 
     public PeopleSpaceWidgetRemoteViewsFactory(Context context, Intent intent) {
@@ -70,8 +70,8 @@
      */
     private void setTileViewsWithPriorityConversations() {
         try {
-            mShortcutInfos = PeopleSpaceUtils.getShortcutInfos(mContext, mNotificationManager,
-                    mPeopleManager);
+            mTiles = PeopleSpaceUtils.getTiles(mContext, mNotificationManager,
+                    mPeopleManager, mLauncherApps);
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve conversations", e);
         }
@@ -85,12 +85,12 @@
 
     @Override
     public void onDestroy() {
-        mShortcutInfos.clear();
+        mTiles.clear();
     }
 
     @Override
     public int getCount() {
-        return mShortcutInfos.size();
+        return mTiles.size();
     }
 
     @Override
@@ -100,30 +100,28 @@
         RemoteViews personView = new RemoteViews(mContext.getPackageName(),
                 R.layout.people_space_widget_item);
         try {
-            Map.Entry<Long, ShortcutInfo> entry = mShortcutInfos.get(i);
-            ShortcutInfo shortcutInfo = entry.getValue();
+            Map.Entry<Long, PeopleSpaceTile> entry = mTiles.get(i);
+            PeopleSpaceTile tile = entry.getValue();
             long lastInteraction = entry.getKey();
 
             String status = PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
 
             personView.setTextViewText(R.id.status, status);
-            personView.setTextViewText(R.id.name, shortcutInfo.getLabel().toString());
+            personView.setTextViewText(R.id.name, tile.getUserName().toString());
 
             personView.setImageViewBitmap(
                     R.id.package_icon,
                     PeopleSpaceUtils.convertDrawableToBitmap(
-                            mPackageManager.getApplicationIcon(shortcutInfo.getPackage())
+                            mPackageManager.getApplicationIcon(tile.getPackageName())
                     )
             );
-            personView.setImageViewBitmap(
-                    R.id.person_icon,
-                    PeopleSpaceUtils.convertDrawableToBitmap(
-                            mLauncherApps.getShortcutIconDrawable(shortcutInfo, 0)
-                    )
-            );
+            personView.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
 
             Intent fillInIntent = new Intent();
-            fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_SHORTCUT_INFO, shortcutInfo);
+            fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
+            fillInIntent.putExtra(
+                    PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
+            fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
             personView.setOnClickFillInIntent(R.id.item, fillInIntent);
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve shortcut information", e);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 4789239..5afe526 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -68,6 +68,7 @@
     private final View mRootView;
     private final TextView mFooterText;
     private final ImageView mFooterIcon;
+    private final ImageView mPrimaryFooterIcon;
     private final Context mContext;
     private final Callback mCallback = new Callback();
     private final SecurityController mSecurityController;
@@ -83,6 +84,7 @@
     private CharSequence mFooterTextContent = null;
     private int mFooterTextId;
     private int mFooterIconId;
+    private Drawable mPrimaryFooterIconDrawable;
 
     @Inject
     QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView, Context context,
@@ -92,6 +94,7 @@
         mRootView.setOnClickListener(this);
         mFooterText = mRootView.findViewById(R.id.footer_text);
         mFooterIcon = mRootView.findViewById(R.id.footer_icon);
+        mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
         mFooterIconId = R.drawable.ic_info_outline;
         mContext = context;
         mMainHandler = mainHandler;
@@ -188,6 +191,18 @@
             mFooterIconId = footerIconId;
             mMainHandler.post(mUpdateIcon);
         }
+
+        // Update the primary icon
+        if (isParentalControlsEnabled) {
+            if (mPrimaryFooterIconDrawable == null) {
+                DeviceAdminInfo info = mSecurityController.getDeviceAdminInfo();
+                mPrimaryFooterIconDrawable = mSecurityController.getIcon(info);
+            }
+        } else {
+            mPrimaryFooterIconDrawable = null;
+        }
+        mMainHandler.post(mUpdatePrimaryIcon);
+
         mMainHandler.post(mUpdateDisplayState);
     }
 
@@ -532,6 +547,15 @@
         }
     };
 
+    private final Runnable mUpdatePrimaryIcon = new Runnable() {
+        @Override
+        public void run() {
+            mPrimaryFooterIcon.setVisibility(mPrimaryFooterIconDrawable != null
+                    ? View.VISIBLE : View.GONE);
+            mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable);
+        }
+    };
+
     private final Runnable mUpdateDisplayState = new Runnable() {
         @Override
         public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index d7a2975..0f0a9a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -134,7 +134,7 @@
         getHost().collapsePanels();
         Intent intent = mController.getPromptIntent();
         ActivityStarter.OnDismissAction dismissAction = () -> {
-            mContext.startActivity(intent);
+            mHost.getUserContext().startActivity(intent);
             return false;
         };
         mKeyguardDismissUtil.executeWhenUnlocked(dismissAction, false);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 10a44dd..7ca8277 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -54,14 +54,31 @@
     private CountDownTimer mCountDownTimer = null;
     private BroadcastDispatcher mBroadcastDispatcher;
 
+    protected static final String INTENT_UPDATE_STATE =
+            "com.android.systemui.screenrecord.UPDATE_STATE";
+    protected static final String EXTRA_STATE = "extra_state";
+
     private ArrayList<RecordingStateChangeCallback> mListeners = new ArrayList<>();
 
     @VisibleForTesting
     protected final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (mStopIntent != null) {
-                stopRecording();
+            stopRecording();
+        }
+    };
+
+    @VisibleForTesting
+    protected final BroadcastReceiver mStateChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent != null && INTENT_UPDATE_STATE.equals(intent.getAction())) {
+                if (intent.hasExtra(EXTRA_STATE)) {
+                    boolean state = intent.getBooleanExtra(EXTRA_STATE, false);
+                    updateState(state);
+                } else {
+                    Log.e(TAG, "Received update intent with no state");
+                }
             }
         }
     };
@@ -118,6 +135,10 @@
                     IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
                     mBroadcastDispatcher.registerReceiver(mUserChangeReceiver, userFilter, null,
                             UserHandle.ALL);
+
+                    IntentFilter stateFilter = new IntentFilter(INTENT_UPDATE_STATE);
+                    mBroadcastDispatcher.registerReceiver(mStateChangeReceiver, stateFilter, null,
+                            UserHandle.ALL);
                     Log.d(TAG, "sent start intent");
                 } catch (PendingIntent.CanceledException e) {
                     Log.e(TAG, "Pending intent was cancelled: " + e.getMessage());
@@ -174,7 +195,6 @@
         } catch (PendingIntent.CanceledException e) {
             Log.e(TAG, "Error stopping: " + e.getMessage());
         }
-        mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver);
     }
 
     /**
@@ -182,6 +202,11 @@
      * @param isRecording
      */
     public synchronized void updateState(boolean isRecording) {
+        if (!isRecording && mIsRecording) {
+            // Unregister receivers if we have stopped recording
+            mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mStateChangeReceiver);
+        }
         mIsRecording = isRecording;
         for (RecordingStateChangeCallback cb : mListeners) {
             if (isRecording) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 3bf118d..1975821 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -69,6 +69,7 @@
     private static final String ACTION_STOP_NOTIF =
             "com.android.systemui.screenrecord.STOP_FROM_NOTIF";
     private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
+    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
     private final RecordingController mController;
     private final KeyguardDismissUtil mKeyguardDismissUtil;
@@ -120,8 +121,8 @@
         String action = intent.getAction();
         Log.d(TAG, "onStartCommand " + action);
 
-        int mCurrentUserId = mUserContextTracker.getUserContext().getUserId();
-        UserHandle currentUser = new UserHandle(mCurrentUserId);
+        int currentUserId = mUserContextTracker.getUserContext().getUserId();
+        UserHandle currentUser = new UserHandle(currentUserId);
         switch (action) {
             case ACTION_START:
                 mAudioSource = ScreenRecordingAudioSource
@@ -137,11 +138,22 @@
 
                 mRecorder = new ScreenMediaRecorder(
                         mUserContextTracker.getUserContext(),
-                        mCurrentUserId,
+                        currentUserId,
                         mAudioSource,
                         this
                 );
-                startRecording();
+
+                if (startRecording()) {
+                    updateState(true);
+                    createRecordingNotification();
+                    mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
+                } else {
+                    updateState(false);
+                    createErrorNotification();
+                    stopForeground(true);
+                    stopSelf();
+                    return Service.START_NOT_STICKY;
+                }
                 break;
 
             case ACTION_STOP_NOTIF:
@@ -201,22 +213,63 @@
         return mRecorder;
     }
 
+    private void updateState(boolean state) {
+        int userId = mUserContextTracker.getUserContext().getUserId();
+        if (userId == UserHandle.USER_SYSTEM) {
+            // Main user has a reference to the correct controller, so no need to use a broadcast
+            mController.updateState(state);
+        } else {
+            Intent intent = new Intent(RecordingController.INTENT_UPDATE_STATE);
+            intent.putExtra(RecordingController.EXTRA_STATE, state);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            sendBroadcast(intent, PERMISSION_SELF);
+        }
+    }
+
     /**
      * Begin the recording session
+     * @return true if successful, false if something went wrong
      */
-    private void startRecording() {
+    private boolean startRecording() {
         try {
             getRecorder().start();
-            mController.updateState(true);
-            createRecordingNotification();
-            mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
-        } catch (IOException | RemoteException | IllegalStateException e) {
-            Toast.makeText(this,
-                    R.string.screenrecord_start_error, Toast.LENGTH_LONG)
-                    .show();
+            return true;
+        } catch (IOException | RemoteException | RuntimeException e) {
+            showErrorToast(R.string.screenrecord_start_error);
             e.printStackTrace();
-            mController.updateState(false);
         }
+        return false;
+    }
+
+    /**
+     * Simple error notification, needed since startForeground must be called to avoid errors
+     */
+    @VisibleForTesting
+    protected void createErrorNotification() {
+        Resources res = getResources();
+        NotificationChannel channel = new NotificationChannel(
+                CHANNEL_ID,
+                getString(R.string.screenrecord_name),
+                NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setDescription(getString(R.string.screenrecord_channel_description));
+        channel.enableVibration(true);
+        mNotificationManager.createNotificationChannel(channel);
+
+        Bundle extras = new Bundle();
+        extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+                res.getString(R.string.screenrecord_name));
+        String notificationTitle = res.getString(R.string.screenrecord_start_error);
+
+        Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
+                .setSmallIcon(R.drawable.ic_screenrecord)
+                .setContentTitle(notificationTitle)
+                .addExtras(extras);
+        startForeground(NOTIFICATION_RECORDING_ID, builder.build());
+    }
+
+    @VisibleForTesting
+    protected void showErrorToast(int stringId) {
+        Toast.makeText(this, stringId, Toast.LENGTH_LONG).show();
     }
 
     @VisibleForTesting
@@ -247,6 +300,7 @@
                 .setColorized(true)
                 .setColor(getResources().getColor(R.color.GM2_red_700))
                 .setOngoing(true)
+                .setShowForegroundImmediately(true)
                 .setContentIntent(
                         PendingIntent.getService(this, REQUEST_CODE, stopIntent,
                                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
@@ -326,7 +380,7 @@
         } else {
             Log.e(TAG, "stopRecording called, but recorder was null");
         }
-        mController.updateState(false);
+        updateState(false);
     }
 
     private void saveRecording(int userId) {
@@ -344,8 +398,7 @@
                 }
             } catch (IOException e) {
                 Log.e(TAG, "Error saving screen recording: " + e.getMessage());
-                Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
-                        .show();
+                showErrorToast(R.string.screenrecord_delete_error);
             } finally {
                 mNotificationManager.cancelAsUser(null, NOTIFICATION_PROCESSING_ID, currentUser);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index 45564b0..9037192 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -94,7 +94,7 @@
         mAudioSource = audioSource;
     }
 
-    private void prepare() throws IOException, RemoteException {
+    private void prepare() throws IOException, RemoteException, RuntimeException {
         //Setup media projection
         IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
         IMediaProjectionManager mediaService =
@@ -257,7 +257,7 @@
     /**
     * Start screen recording
     */
-    void start() throws IOException, RemoteException, IllegalStateException {
+    void start() throws IOException, RemoteException, RuntimeException {
         Log.d(TAG, "start recording");
         prepare();
         mMediaRecorder.start();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 35874cd..1e91673 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -19,6 +19,8 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
 
 import static java.util.Objects.requireNonNull;
 
@@ -52,7 +54,8 @@
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.view.View;
-import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -60,6 +63,7 @@
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.logging.UiEventLogger;
+import com.android.internal.policy.PhoneWindow;
 import com.android.systemui.R;
 import com.android.systemui.util.DeviceConfigProxy;
 
@@ -147,6 +151,8 @@
     private final MediaActionSound mCameraSound;
     private final ScrollCaptureClient mScrollCaptureClient;
     private final DeviceConfigProxy mConfigProxy;
+    private final PhoneWindow mWindow;
+    private final View mDecorView;
 
     private final Binder mWindowToken;
     private ScreenshotView mScreenshotView;
@@ -189,13 +195,12 @@
 
         final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class));
         mDisplay = dm.getDisplay(DEFAULT_DISPLAY);
-        mContext = context.createDisplayContext(mDisplay);
+        mContext = context.createWindowContext(TYPE_SCREENSHOT, null);
         mWindowManager = mContext.getSystemService(WindowManager.class);
 
         mAccessibilityManager = AccessibilityManager.getInstance(mContext);
         mConfigProxy = configProxy;
 
-        reloadAssets();
         Configuration config = mContext.getResources().getConfiguration();
         mInDarkMode = config.isNightModeActive();
         mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
@@ -204,9 +209,8 @@
         mScrollCaptureClient.setHostWindowToken(mWindowToken);
 
         // Setup the window that we are going to use
-        mWindowLayoutParams = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
-                WindowManager.LayoutParams.TYPE_SCREENSHOT,
+        mWindowLayoutParams = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, 0, 0,
+                TYPE_SCREENSHOT,
                 WindowManager.LayoutParams.FLAG_FULLSCREEN
                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -217,11 +221,19 @@
         mWindowLayoutParams.setTitle("ScreenshotAnimation");
         mWindowLayoutParams.layoutInDisplayCutoutMode =
                 WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
         mWindowLayoutParams.token = mWindowToken;
         // This is needed to let touches pass through outside the touchable areas
         mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 
+        mWindow = new PhoneWindow(mContext);
+        mWindow.setWindowManager(mWindowManager, null, null);
+        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+        mWindow.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
+        mWindow.setBackgroundDrawableResource(android.R.color.transparent);
+        mDecorView = mWindow.getDecorView();
+
+        reloadAssets();
+
         mDisplayMetrics = new DisplayMetrics();
         mDisplay.getRealMetrics(mDisplayMetrics);
 
@@ -355,11 +367,21 @@
      * button and the actions container background, since the buttons are re-inflated on demand.
      */
     private void reloadAssets() {
-        boolean wasAttached = mScreenshotView != null && mScreenshotView.isAttachedToWindow();
+        boolean wasAttached = mDecorView.isAttachedToWindow();
         if (wasAttached) {
-            mWindowManager.removeView(mScreenshotView);
+            mWindowManager.removeView(mDecorView);
         }
 
+        // respect the display cutout in landscape (since we'd otherwise overlap) but not portrait
+        mWindowLayoutParams.setFitInsetsTypes(
+                mOrientationPortrait ? 0 : WindowInsets.Type.displayCutout());
+
+        // ignore system bar insets for the purpose of window layout
+        mDecorView.setOnApplyWindowInsetsListener((v, insets) -> v.onApplyWindowInsets(
+                new WindowInsets.Builder(insets)
+                        .setInsets(WindowInsets.Type.all(), Insets.NONE)
+                        .build()));
+
         // Inflate the screenshot layout
         mScreenshotView = (ScreenshotView)
                 LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
@@ -382,9 +404,8 @@
             return false;
         });
 
-        if (wasAttached) {
-            mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
-        }
+        // view is added to window manager in startAnimation
+        mWindow.setContentView(mScreenshotView, mWindowLayoutParams);
     }
 
     /**
@@ -510,10 +531,10 @@
         mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
         mScreenshotHandler.post(() -> {
             if (!mScreenshotView.isAttachedToWindow()) {
-                mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
+                mWindowManager.addView(mWindow.getDecorView(), mWindowLayoutParams);
             }
 
-            mScreenshotView.prepareForAnimation(mScreenBitmap, screenRect, screenInsets);
+            mScreenshotView.prepareForAnimation(mScreenBitmap, screenInsets);
 
             mScreenshotHandler.post(() -> {
                 mScreenshotView.getViewTreeObserver().addOnComputeInternalInsetsListener(
@@ -541,7 +562,7 @@
 
     private void resetScreenshotView() {
         if (mScreenshotView.isAttachedToWindow()) {
-            mWindowManager.removeView(mScreenshotView);
+            mWindowManager.removeView(mDecorView);
         }
         mScreenshotView.reset();
         mOnCompleteRunnable.run();
@@ -636,8 +657,8 @@
         } else {
             mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
         }
-        if (mScreenshotView.isAttachedToWindow()) {
-            mWindowManager.updateViewLayout(mScreenshotView, mWindowLayoutParams);
+        if (mDecorView.isAttachedToWindow()) {
+            mWindowManager.updateViewLayout(mDecorView, mWindowLayoutParams);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index b020275..3814bd2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -240,8 +240,7 @@
 
         setOnApplyWindowInsetsListener((v, insets) -> {
             if (QuickStepContract.isGesturalMode(mNavMode)) {
-                Insets gestureInsets = insets.getInsets(
-                        WindowInsets.Type.systemGestures());
+                Insets gestureInsets = insets.getInsets(WindowInsets.Type.systemGestures());
                 mLeftInset = gestureInsets.left;
                 mRightInset = gestureInsets.right;
             } else {
@@ -272,7 +271,7 @@
         mScreenshotSelectorView.requestFocus();
     }
 
-    void prepareForAnimation(Bitmap bitmap, Rect screenRect, Insets screenInsets) {
+    void prepareForAnimation(Bitmap bitmap, Insets screenInsets) {
         mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
         // make static preview invisible (from gone) so we can query its location on screen
         mScreenshotPreview.setVisibility(View.INVISIBLE);
@@ -284,6 +283,8 @@
 
         Rect previewBounds = new Rect();
         mScreenshotPreview.getBoundsOnScreen(previewBounds);
+        int[] previewLocation = new int[2];
+        mScreenshotPreview.getLocationInWindow(previewLocation);
 
         float cornerScale =
                 mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
@@ -310,7 +311,8 @@
 
         // animate from the current location, to the static preview location
         final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
-        final PointF finalPos = new PointF(previewBounds.centerX(), previewBounds.centerY());
+        final PointF finalPos = new PointF(previewLocation[0] + previewBounds.width() / 2f,
+                previewLocation[1] + previewBounds.height() / 2f);
 
         ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
         toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 672f82c..2c82bcb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -43,6 +43,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.ScreenshotHelper;
+import com.android.systemui.R;
 import com.android.systemui.shared.recents.utilities.BitmapUtil;
 
 import java.util.function.Consumer;
@@ -55,6 +56,7 @@
     private final ScreenshotController mScreenshot;
     private final UserManager mUserManager;
     private final UiEventLogger mUiEventLogger;
+    private final ScreenshotNotificationsController mNotificationsController;
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
 
@@ -90,6 +92,8 @@
             // animation and error notification.
             if (!mUserManager.isUserUnlocked()) {
                 Log.w(TAG, "Skipping screenshot because storage is locked!");
+                mNotificationsController.notifyScreenshotError(
+                        R.string.screenshot_failed_to_save_user_locked_text);
                 post(() -> uriConsumer.accept(null));
                 post(onComplete);
                 return;
@@ -125,11 +129,15 @@
     };
 
     @Inject
-    public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager,
-            UiEventLogger uiEventLogger) {
+    public TakeScreenshotService(
+            ScreenshotController screenshotController,
+            UserManager userManager,
+            UiEventLogger uiEventLogger,
+            ScreenshotNotificationsController notificationsController) {
         mScreenshot = screenshotController;
         mUserManager = userManager;
         mUiEventLogger = uiEventLogger;
+        mNotificationsController = notificationsController;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index e61e05a..7ef88bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -31,6 +31,7 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
@@ -46,6 +47,7 @@
     private static final int SPRING_BACK_ANIMATION_LENGTH_MS = 375;
 
     private int mMinDragDistance;
+    private final FalsingManager mFalsingManager;
     private ExpandHelper.Callback mCallback;
     private float mInitialTouchX;
     private float mInitialTouchY;
@@ -58,20 +60,21 @@
     private boolean mDraggedFarEnough;
     private ExpandableView mStartingChild;
     private float mLastHeight;
-    private FalsingManager mFalsingManager;
+    private FalsingCollector mFalsingCollector;
 
     public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
-            DragDownCallback dragDownCallback,
-            FalsingManager falsingManager) {
+            DragDownCallback dragDownCallback, FalsingManager falsingManager,
+            FalsingCollector falsingCollector) {
         mMinDragDistance = context.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_drag_down_min_distance);
+        mFalsingManager = falsingManager;
         final ViewConfiguration configuration = ViewConfiguration.get(context);
         mTouchSlop = configuration.getScaledTouchSlop();
         mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
         mCallback = callback;
         mDragDownCallback = dragDownCallback;
         mHost = host;
-        mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
     }
 
     @Override
@@ -96,7 +99,7 @@
                         ? mTouchSlop * mSlopMultiplier
                         : mTouchSlop;
                 if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) {
-                    mFalsingManager.onNotificatonStartDraggingDown();
+                    mFalsingCollector.onNotificationStartDraggingDown();
                     mDraggingDown = true;
                     captureStartingChild(mInitialTouchX, mInitialTouchY);
                     mInitialTouchY = y;
@@ -229,7 +232,7 @@
     }
 
     private void stopDragging() {
-        mFalsingManager.onNotificatonStopDraggingDown();
+        mFalsingCollector.onNotificationStopDraggingDown();
         if (mStartingChild != null) {
             cancelExpansion(mStartingChild);
             mStartingChild = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
similarity index 62%
rename from packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
index 84818ee..dbee0ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,19 +11,22 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.systemui.statusbar;
 
 import android.app.Notification;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.text.TextUtils;
+import android.view.NotificationHeaderView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.R;
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.ConversationLayout;
 import com.android.internal.widget.NotificationExpandButton;
@@ -36,35 +39,38 @@
 import java.util.Objects;
 
 /**
- * A Util to manage {@link android.view.NotificationHeaderView} objects and their redundancies.
+ * A utility to manage notification views when they are placed in a group by adjusting elements
+ * to reduce redundancies and occasionally tweak layouts to highlight the unique content.
  */
-public class NotificationHeaderUtil {
+public class NotificationGroupingUtil {
 
-    private static final TextViewComparator sTextViewComparator = new TextViewComparator();
-    private static final TextViewComparator sAppNameComparator = new AppNameComparator();
-    private static final VisibilityApplicator sVisibilityApplicator = new VisibilityApplicator();
-    private static final VisibilityApplicator sAppNameApplicator = new AppNameApplicator();
-    private static  final DataExtractor sIconExtractor = new DataExtractor() {
+    private static final TextViewComparator TEXT_VIEW_COMPARATOR = new TextViewComparator();
+    private static final TextViewComparator APP_NAME_COMPARATOR = new AppNameComparator();
+    private static final ViewComparator BADGE_COMPARATOR = new BadgeComparator();
+    private static final VisibilityApplicator VISIBILITY_APPLICATOR = new VisibilityApplicator();
+    private static final VisibilityApplicator APP_NAME_APPLICATOR = new AppNameApplicator();
+    private static final ResultApplicator LEFT_ICON_APPLICATOR = new LeftIconApplicator();
+    private static final DataExtractor ICON_EXTRACTOR = new DataExtractor() {
         @Override
         public Object extractData(ExpandableNotificationRow row) {
             return row.getEntry().getSbn().getNotification();
         }
     };
-    private static final IconComparator sIconVisibilityComparator = new IconComparator() {
+    private static final IconComparator ICON_VISIBILITY_COMPARATOR = new IconComparator() {
         public boolean compare(View parent, View child, Object parentData,
                 Object childData) {
             return hasSameIcon(parentData, childData)
                     && hasSameColor(parentData, childData);
         }
     };
-    private static final IconComparator sGreyComparator = new IconComparator() {
+    private static final IconComparator GREY_COMPARATOR = new IconComparator() {
         public boolean compare(View parent, View child, Object parentData,
                 Object childData) {
             return !hasSameIcon(parentData, childData)
                     || hasSameColor(parentData, childData);
         }
     };
-    private final static ResultApplicator mGreyApplicator = new ResultApplicator() {
+    private static final ResultApplicator GREY_APPLICATOR = new ResultApplicator() {
         @Override
         public void apply(View parent, View view, boolean apply, boolean reset) {
             CachingIconView icon = view.findViewById(com.android.internal.R.id.icon);
@@ -80,87 +86,79 @@
     };
 
     private final ExpandableNotificationRow mRow;
-    private final ArrayList<HeaderProcessor> mComparators = new ArrayList<>();
+    private final ArrayList<Processor> mProcessors = new ArrayList<>();
     private final HashSet<Integer> mDividers = new HashSet<>();
 
-    public NotificationHeaderUtil(ExpandableNotificationRow row) {
+    public NotificationGroupingUtil(ExpandableNotificationRow row) {
         mRow = row;
         // To hide the icons if they are the same and the color is the same
-        mComparators.add(new HeaderProcessor(mRow,
+        mProcessors.add(new Processor(mRow,
                 com.android.internal.R.id.icon,
-                sIconExtractor,
-                sIconVisibilityComparator,
-                sVisibilityApplicator));
+                ICON_EXTRACTOR,
+                ICON_VISIBILITY_COMPARATOR,
+                VISIBILITY_APPLICATOR));
         // To grey them out the icons and expand button when the icons are not the same
-        mComparators.add(new HeaderProcessor(mRow,
-                com.android.internal.R.id.notification_header,
-                sIconExtractor,
-                sGreyComparator,
-                mGreyApplicator));
-        mComparators.add(new HeaderProcessor(mRow,
+        mProcessors.add(new Processor(mRow,
+                com.android.internal.R.id.status_bar_latest_event_content,
+                ICON_EXTRACTOR,
+                GREY_COMPARATOR,
+                GREY_APPLICATOR));
+        mProcessors.add(new Processor(mRow,
+                com.android.internal.R.id.status_bar_latest_event_content,
+                ICON_EXTRACTOR,
+                ICON_VISIBILITY_COMPARATOR,
+                LEFT_ICON_APPLICATOR));
+        mProcessors.add(new Processor(mRow,
                 com.android.internal.R.id.profile_badge,
                 null /* Extractor */,
-                new ViewComparator() {
-                    @Override
-                    public boolean compare(View parent, View child, Object parentData,
-                            Object childData) {
-                        return parent.getVisibility() != View.GONE;
-                    }
-
-                    @Override
-                    public boolean isEmpty(View view) {
-                        if (view instanceof ImageView) {
-                            return ((ImageView) view).getDrawable() == null;
-                        }
-                        return false;
-                    }
-                },
-                sVisibilityApplicator));
-        mComparators.add(new HeaderProcessor(
-                mRow,
+                BADGE_COMPARATOR,
+                VISIBILITY_APPLICATOR));
+        mProcessors.add(new Processor(mRow,
                 com.android.internal.R.id.app_name_text,
                 null,
-                sAppNameComparator,
-                sAppNameApplicator));
-        mComparators.add(HeaderProcessor.forTextView(mRow,
-                com.android.internal.R.id.header_text));
+                APP_NAME_COMPARATOR,
+                APP_NAME_APPLICATOR));
+        mProcessors.add(Processor.forTextView(mRow, com.android.internal.R.id.header_text));
         mDividers.add(com.android.internal.R.id.header_text_divider);
         mDividers.add(com.android.internal.R.id.header_text_secondary_divider);
         mDividers.add(com.android.internal.R.id.time_divider);
     }
 
-    public void updateChildrenHeaderAppearance() {
+    /**
+     * Update the appearance of the children in this group to reduce redundancies.
+     */
+    public void updateChildrenAppearance() {
         List<ExpandableNotificationRow> notificationChildren = mRow.getAttachedChildren();
-        if (notificationChildren == null) {
+        if (notificationChildren == null || !mRow.isSummaryWithChildren()) {
             return;
         }
-        // Initialize the comparators
-        for (int compI = 0; compI < mComparators.size(); compI++) {
-            mComparators.get(compI).init();
+        // Initialize the processors
+        for (int compI = 0; compI < mProcessors.size(); compI++) {
+            mProcessors.get(compI).init();
         }
 
         // Compare all notification headers
         for (int i = 0; i < notificationChildren.size(); i++) {
             ExpandableNotificationRow row = notificationChildren.get(i);
-            for (int compI = 0; compI < mComparators.size(); compI++) {
-                mComparators.get(compI).compareToHeader(row);
+            for (int compI = 0; compI < mProcessors.size(); compI++) {
+                mProcessors.get(compI).compareToGroupParent(row);
             }
         }
 
         // Apply the comparison to the row
         for (int i = 0; i < notificationChildren.size(); i++) {
             ExpandableNotificationRow row = notificationChildren.get(i);
-            for (int compI = 0; compI < mComparators.size(); compI++) {
-                mComparators.get(compI).apply(row);
+            for (int compI = 0; compI < mProcessors.size(); compI++) {
+                mProcessors.get(compI).apply(row);
             }
             // We need to sanitize the dividers since they might be off-balance now
-            sanitizeHeaderViews(row);
+            sanitizeTopLineViews(row);
         }
     }
 
-    private void sanitizeHeaderViews(ExpandableNotificationRow row) {
+    private void sanitizeTopLineViews(ExpandableNotificationRow row) {
         if (row.isSummaryWithChildren()) {
-            sanitizeHeader(row.getNotificationViewWrapper().getNotificationHeader());
+            sanitizeTopLine(row.getNotificationViewWrapper().getNotificationHeader());
             return;
         }
         final NotificationContentView layout = row.getPrivateLayout();
@@ -171,13 +169,11 @@
 
     private void sanitizeChild(View child) {
         if (child != null) {
-            ViewGroup header = child.findViewById(
-                    com.android.internal.R.id.notification_top_line);
-            sanitizeHeader(header);
+            sanitizeTopLine(child.findViewById(R.id.notification_top_line));
         }
     }
 
-    private void sanitizeHeader(ViewGroup rowHeader) {
+    private void sanitizeTopLine(ViewGroup rowHeader) {
         if (rowHeader == null) {
             return;
         }
@@ -225,28 +221,31 @@
         }
     }
 
-    public void restoreNotificationHeader(ExpandableNotificationRow row) {
-        for (int compI = 0; compI < mComparators.size(); compI++) {
-            mComparators.get(compI).apply(row, true /* reset */);
+    /**
+     * Reset the modifications to this row for removing it from the group.
+     */
+    public void restoreChildNotification(ExpandableNotificationRow row) {
+        for (int compI = 0; compI < mProcessors.size(); compI++) {
+            mProcessors.get(compI).apply(row, true /* reset */);
         }
-        sanitizeHeaderViews(row);
+        sanitizeTopLineViews(row);
     }
 
-    private static class HeaderProcessor {
+    private static class Processor {
         private final int mId;
         private final DataExtractor mExtractor;
+        private final ViewComparator mComparator;
         private final ResultApplicator mApplicator;
         private final ExpandableNotificationRow mParentRow;
         private boolean mApply;
         private View mParentView;
-        private ViewComparator mComparator;
         private Object mParentData;
 
-        public static HeaderProcessor forTextView(ExpandableNotificationRow row, int id) {
-            return new HeaderProcessor(row, id, null, sTextViewComparator, sVisibilityApplicator);
+        public static Processor forTextView(ExpandableNotificationRow row, int id) {
+            return new Processor(row, id, null, TEXT_VIEW_COMPARATOR, VISIBILITY_APPLICATOR);
         }
 
-        HeaderProcessor(ExpandableNotificationRow row, int id, DataExtractor extractor,
+        Processor(ExpandableNotificationRow row, int id, DataExtractor extractor,
                 ViewComparator comparator,
                 ResultApplicator applicator) {
             mId = id;
@@ -257,12 +256,12 @@
         }
 
         public void init() {
-            mParentView = mParentRow.getNotificationViewWrapper().getNotificationHeader()
-                    .findViewById(mId);
+            View header = mParentRow.getNotificationViewWrapper().getNotificationHeader();
+            mParentView = header == null ? null : header.findViewById(mId);
             mParentData = mExtractor == null ? null : mExtractor.extractData(mParentRow);
             mApply = !mComparator.isEmpty(mParentView);
         }
-        public void compareToHeader(ExpandableNotificationRow row) {
+        public void compareToGroupParent(ExpandableNotificationRow row) {
             if (!mApply) {
                 return;
             }
@@ -308,8 +307,8 @@
 
     private interface ViewComparator {
         /**
-         * @param parent the parent view
-         * @param child the child view
+         * @param parent the view with the given id in the group header
+         * @param child the view with the given id in the child notification
          * @param parentData optional data for the parent
          * @param childData optional data for the child
          * @return whether to views are the same
@@ -322,6 +321,21 @@
         Object extractData(ExpandableNotificationRow row);
     }
 
+    private static class BadgeComparator implements ViewComparator {
+        @Override
+        public boolean compare(View parent, View child, Object parentData, Object childData) {
+            return parent.getVisibility() != View.GONE;
+        }
+
+        @Override
+        public boolean isEmpty(View view) {
+            if (view instanceof ImageView) {
+                return ((ImageView) view).getDrawable() == null;
+            }
+            return false;
+        }
+    }
+
     private static class TextViewComparator implements ViewComparator {
         @Override
         public boolean compare(View parent, View child, Object parentData, Object childData) {
@@ -338,7 +352,7 @@
         }
     }
 
-    private static abstract class IconComparator implements ViewComparator {
+    private abstract static class IconComparator implements ViewComparator {
         @Override
         public boolean compare(View parent, View child, Object parentData, Object childData) {
             return false;
@@ -366,6 +380,12 @@
     }
 
     private interface ResultApplicator {
+        /**
+         * @param parent the root view of the child notification
+         * @param view the view with the given id in the child notification
+         * @param apply whether the state should be applied or removed
+         * @param reset if [de]application is the result of a reset
+         */
         void apply(View parent, View view, boolean apply, boolean reset);
     }
 
@@ -403,4 +423,54 @@
             return super.compare(parent, child, parentData, childData);
         }
     }
+
+    private static class LeftIconApplicator implements ResultApplicator {
+
+        public static final int[] MARGIN_ADJUSTED_VIEWS = {
+                R.id.notification_headerless_view_column,
+                R.id.line1,
+                R.id.notification_main_column,
+                R.id.notification_header};
+
+        @Override
+        public void apply(View parent, View child, boolean apply, boolean reset) {
+            ImageView rightIcon = child.findViewById(com.android.internal.R.id.right_icon);
+            ImageView leftIcon = child.findViewById(com.android.internal.R.id.left_icon);
+            if (rightIcon == null || leftIcon == null) {
+                return;
+            }
+            Drawable iconDrawable = rightIcon.getDrawable();
+            if (iconDrawable == null) {
+                return;
+            }
+            rightIcon.setVisibility(apply ? View.GONE : View.VISIBLE);
+            leftIcon.setVisibility(apply ? View.VISIBLE : View.GONE);
+            leftIcon.setImageDrawable(apply ? iconDrawable : null);
+
+            for (int viewId : MARGIN_ADJUSTED_VIEWS) {
+                adjustMargins(!apply, child.findViewById(viewId));
+            }
+        }
+
+        void adjustMargins(boolean iconVisible, View target) {
+            if (target == null) {
+                return;
+            }
+            Integer value = (Integer) target.getTag(iconVisible
+                    ? com.android.internal.R.id.tag_margin_end_when_icon_visible
+                    : com.android.internal.R.id.tag_margin_end_when_icon_gone);
+            if (value == null) {
+                return;
+            }
+            if (target instanceof NotificationHeaderView) {
+                ((NotificationHeaderView) target).setTopLineExtraMarginEnd(value);
+            } else {
+                ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
+                if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
+                    ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value);
+                    target.setLayoutParams(layoutParams);
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 6fa3633..b7343f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.Interpolators
 import com.android.systemui.R
 import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
+import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -57,7 +58,8 @@
     private val headsUpManager: HeadsUpManagerPhone,
     private val roundnessManager: NotificationRoundnessManager,
     private val statusBarStateController: StatusBarStateController,
-    private val falsingManager: FalsingManager
+    private val falsingManager: FalsingManager,
+    private val falsingCollector: FalsingCollector
 ) : Gefingerpoken {
     companion object {
         private val RUBBERBAND_FACTOR_STATIC = 0.25f
@@ -148,7 +150,7 @@
             MotionEvent.ACTION_MOVE -> {
                 val h = y - mInitialTouchY
                 if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
-                    falsingManager.onStartExpandingFromPulse()
+                    falsingCollector.onStartExpandingFromPulse()
                     isExpanding = true
                     captureStartingChild(mInitialTouchX, mInitialTouchY)
                     mInitialTouchY = y
@@ -301,7 +303,7 @@
 
     private fun cancelExpansion() {
         isExpanding = false
-        falsingManager.onExpansionFromPulseStopped()
+        falsingCollector.onExpansionFromPulseStopped()
         if (mStartingChild != null) {
             reset(mStartingChild!!)
             mStartingChild = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
index 967524c..ecd0c41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
@@ -40,6 +40,14 @@
             View.TRANSLATION_X, R.id.x_animator_tag, R.id.x_animator_tag_start_value,
             R.id.x_animator_tag_end_value);
 
+    public static final AnimatableProperty SCALE_X = AnimatableProperty.from(
+            View.SCALE_X, R.id.scale_x_animator_tag, R.id.scale_x_animator_start_value_tag,
+            R.id.scale_x_animator_end_value_tag);
+
+    public static final AnimatableProperty SCALE_Y = AnimatableProperty.from(
+            View.SCALE_Y, R.id.scale_y_animator_tag, R.id.scale_y_animator_start_value_tag,
+            R.id.scale_y_animator_end_value_tag);
+
     /**
      * Similar to X, however this doesn't allow for any other modifications other than from this
      * property. When using X, it's possible that the view is laid out during the animation,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 44b9bd2..d1ab7ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -19,18 +19,25 @@
 import android.app.Notification
 import android.content.Context
 import android.content.pm.LauncherApps
+import android.graphics.drawable.AnimatedImageDrawable
 import android.os.Handler
 import android.service.notification.NotificationListenerService.Ranking
 import android.service.notification.NotificationListenerService.RankingMap
 import com.android.internal.statusbar.NotificationVisibility
 import com.android.internal.widget.ConversationLayout
+import com.android.internal.widget.MessagingImageMessage
+import com.android.internal.widget.MessagingLayout
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationContentView
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
+import com.android.systemui.util.children
 import java.util.concurrent.ConcurrentHashMap
 import javax.inject.Inject
 
@@ -58,6 +65,71 @@
 }
 
 /**
+ * Tracks state related to animated images inside of notifications. Ex: starting and stopping
+ * animations to conserve CPU and memory.
+ */
+@SysUISingleton
+class AnimatedImageNotificationManager @Inject constructor(
+    private val notificationEntryManager: NotificationEntryManager,
+    private val headsUpManager: HeadsUpManager,
+    private val statusBarStateController: StatusBarStateController
+) {
+
+    private var isStatusBarExpanded = false
+
+    /** Begins listening to state changes and updating animations accordingly. */
+    fun bind() {
+        headsUpManager.addListener(object : OnHeadsUpChangedListener {
+            override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
+                entry.row?.let { row ->
+                    updateAnimatedImageDrawables(row, animating = isHeadsUp || isStatusBarExpanded)
+                }
+            }
+        })
+        statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+            override fun onExpandedChanged(isExpanded: Boolean) {
+                isStatusBarExpanded = isExpanded
+                notificationEntryManager.activeNotificationsForCurrentUser.forEach { entry ->
+                    entry.row?.let { row ->
+                        updateAnimatedImageDrawables(row, animating = isExpanded || row.isHeadsUp)
+                    }
+                }
+            }
+        })
+        notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
+            override fun onEntryInflated(entry: NotificationEntry) {
+                entry.row?.let { row ->
+                    updateAnimatedImageDrawables(
+                            row,
+                            animating = isStatusBarExpanded || row.isHeadsUp)
+                }
+            }
+            override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry)
+        })
+    }
+
+    private fun updateAnimatedImageDrawables(row: ExpandableNotificationRow, animating: Boolean) =
+            (row.layouts?.asSequence() ?: emptySequence())
+                    .flatMap { layout -> layout.allViews.asSequence() }
+                    .flatMap { view ->
+                        (view as? ConversationLayout)?.messagingGroups?.asSequence()
+                                ?: (view as? MessagingLayout)?.messagingGroups?.asSequence()
+                                ?: emptySequence()
+                    }
+                    .flatMap { messagingGroup -> messagingGroup.messageContainer.children }
+                    .mapNotNull { view ->
+                        (view as? MessagingImageMessage)
+                                ?.let { imageMessage ->
+                                    imageMessage.drawable as? AnimatedImageDrawable
+                                }
+                    }
+                    .forEach { animatedImageDrawable ->
+                        if (animating) animatedImageDrawable.start()
+                        else animatedImageDrawable.stop()
+                    }
+}
+
+/**
  * Tracks state related to conversation notifications, and updates the UI of existing notifications
  * when necessary.
  */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 363a085..1f9bc77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -364,18 +364,13 @@
 
     @Nullable
     private Intent getTaskIntent(int taskId, int userId) {
-        try {
-            final List<ActivityManager.RecentTaskInfo> tasks =
-                    ActivityTaskManager.getService()
-                            .getRecentTasks(NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId)
-                            .getList();
-            for (int i = 0; i < tasks.size(); i++) {
-                if (tasks.get(i).id == taskId) {
-                    return tasks.get(i).baseIntent;
-                }
+        final List<ActivityManager.RecentTaskInfo> tasks =
+                ActivityTaskManager.getInstance().getRecentTasks(
+                        NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId);
+        for (int i = 0; i < tasks.size(); i++) {
+            if (tasks.get(i).id == taskId) {
+                return tasks.get(i).baseIntent;
             }
-        } catch (RemoteException e) {
-            // Fall through
         }
         return null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 8f352ad..54ce4ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.FeatureFlags
 import com.android.systemui.statusbar.NotificationListener
 import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.NotificationClicker
 import com.android.systemui.statusbar.notification.NotificationEntryManager
@@ -71,7 +72,8 @@
     private val headsUpManager: HeadsUpManager,
     private val headsUpController: HeadsUpController,
     private val headsUpViewBinder: HeadsUpViewBinder,
-    private val clickerBuilder: NotificationClicker.Builder
+    private val clickerBuilder: NotificationClicker.Builder,
+    private val animatedImageNotificationManager: AnimatedImageNotificationManager
 ) : NotificationsController {
 
     override fun initialize(
@@ -100,6 +102,7 @@
                 bindRowCallback)
         headsUpViewBinder.setPresenter(presenter)
         notifBindPipelineInitializer.initialize()
+        animatedImageNotificationManager.bind()
 
         if (featureFlags.isNewNotifPipelineEnabled) {
             newNotifPipeline.get().initialize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index 0b79387..50bbc38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -22,6 +22,7 @@
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.systemui.Gefingerpoken;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.phone.NotificationTapHelper;
 import com.android.systemui.util.ViewController;
@@ -36,6 +37,7 @@
     private final ExpandableOutlineViewController mExpandableOutlineViewController;
     private final AccessibilityManager mAccessibilityManager;
     private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
     private final NotificationTapHelper mNotificationTapHelper;
     private final TouchHandler mTouchHandler = new TouchHandler();
 
@@ -45,17 +47,19 @@
     public ActivatableNotificationViewController(ActivatableNotificationView view,
             NotificationTapHelper.Factory notificationTapHelpFactory,
             ExpandableOutlineViewController expandableOutlineViewController,
-            AccessibilityManager accessibilityManager, FalsingManager falsingManager) {
+            AccessibilityManager accessibilityManager, FalsingManager falsingManager,
+            FalsingCollector falsingCollector) {
         super(view);
         mExpandableOutlineViewController = expandableOutlineViewController;
         mAccessibilityManager = accessibilityManager;
         mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
 
         mNotificationTapHelper = notificationTapHelpFactory.create(
                 (active) -> {
                     if (active) {
                         mView.makeActive();
-                        mFalsingManager.onNotificationActive();
+                        mFalsingCollector.onNotificationActive();
                     } else {
                         mView.makeInactive(true /* animate */);
                     }
@@ -64,7 +68,7 @@
         mView.setOnActivatedListener(new ActivatableNotificationView.OnActivatedListener() {
             @Override
             public void onActivated(ActivatableNotificationView view) {
-                mFalsingManager.onNotificationActive();
+                mFalsingCollector.onNotificationActive();
             }
 
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 5682c88..10118e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -43,7 +43,6 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
 import android.util.AttributeSet;
@@ -74,7 +73,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
@@ -213,7 +212,7 @@
     private NotificationGuts mGuts;
     private NotificationEntry mEntry;
     private String mAppName;
-    private FalsingManager mFalsingManager;
+    private FalsingCollector mFalsingCollector;
 
     /**
      * Whether or not the notification is using the heads up view and should peek from the top.
@@ -559,7 +558,7 @@
             setChronometerRunning(true);
         }
         if (mNotificationParent != null) {
-            mNotificationParent.updateChildrenHeaderAppearance();
+            mNotificationParent.updateChildrenAppearance();
         }
         onAttachedChildrenCountChanged();
         // The public layouts expand button is always visible
@@ -1584,7 +1583,7 @@
             OnExpandClickListener onExpandClickListener,
             NotificationMediaManager notificationMediaManager,
             CoordinateOnClickListener onFeedbackClickListener,
-            FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             StatusBarStateController statusBarStateController,
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             OnUserInteractionCallback onUserInteractionCallback,
@@ -1609,7 +1608,7 @@
         mOnExpandClickListener = onExpandClickListener;
         mMediaManager = notificationMediaManager;
         setOnFeedbackClickListener(onFeedbackClickListener);
-        mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
         mStatusBarStateController = statusBarStateController;
 
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
@@ -2176,7 +2175,7 @@
      * @param allowChildExpansion whether a call to this method allows expanding children
      */
     public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
-        mFalsingManager.setNotificationExpanded();
+        mFalsingCollector.setNotificationExpanded();
         if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
                 && !mChildrenContainer.showingAsLowPriority()) {
             final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
@@ -2338,7 +2337,7 @@
         }
         getShowingLayout().updateBackgroundColor(false /* animate */);
         mPrivateLayout.updateExpandButtons(isExpandable());
-        updateChildrenHeaderAppearance();
+        updateChildrenAppearance();
         updateChildrenVisibility();
         applyChildrenRoundness();
     }
@@ -2383,9 +2382,12 @@
         return channels;
     }
 
-    public void updateChildrenHeaderAppearance() {
+    /**
+     * If this is a group, update the appearance of the children.
+     */
+    public void updateChildrenAppearance() {
         if (mIsSummaryWithChildren) {
-            mChildrenContainer.updateChildrenHeaderAppearance();
+            mChildrenContainer.updateChildrenAppearance();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index cb2af54..0d0e97e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -25,7 +25,7 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
@@ -78,7 +78,7 @@
     private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
     private final NotificationGutsManager mNotificationGutsManager;
     private final OnUserInteractionCallback mOnUserInteractionCallback;
-    private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
     private final boolean mAllowLongPress;
     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     private final Optional<BubblesManager> mBubblesManagerOptional;
@@ -104,7 +104,7 @@
             NotificationGutsManager notificationGutsManager,
             @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
             OnUserInteractionCallback onUserInteractionCallback,
-            FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             Optional<BubblesManager> bubblesManagerOptional) {
         mView = view;
@@ -127,7 +127,7 @@
         mOnUserInteractionCallback = onUserInteractionCallback;
         mOnFeedbackClickListener = mNotificationGutsManager::openGuts;
         mAllowLongPress = allowLongPress;
-        mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
         mBubblesManagerOptional = bubblesManagerOptional;
     }
@@ -150,7 +150,7 @@
                 mOnExpandClickListener,
                 mMediaManager,
                 mOnFeedbackClickListener,
-                mFalsingManager,
+                mFalsingCollector,
                 mStatusBarStateController,
                 mPeopleNotificationIdentifier,
                 mOnUserInteractionCallback,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index 7bd192d..44ccb68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -19,10 +19,7 @@
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
@@ -81,7 +78,7 @@
      * @return True if has its internal cache, false otherwise.
      */
     public boolean hasCache() {
-        return mImageCache != null && !ActivityManager.isLowRamDeviceStatic();
+        return mImageCache != null && !isLowRam();
     }
 
     private boolean isLowRam() {
@@ -110,11 +107,6 @@
                 : R.dimen.notification_custom_view_max_image_height);
     }
 
-    @VisibleForTesting
-    protected BitmapDrawable resolveImageInternal(Uri uri) throws IOException {
-        return (BitmapDrawable) LocalImageResolver.resolveImage(uri, mContext);
-    }
-
     /**
      * To resolve image from specified uri directly. If the resulting image is larger than the
      * maximum allowed size, scale it down.
@@ -123,13 +115,7 @@
      * @throws IOException Throws if failed at resolving the image.
      */
     Drawable resolveImage(Uri uri) throws IOException {
-        BitmapDrawable image = resolveImageInternal(uri);
-        if (image == null || image.getBitmap() == null) {
-            throw new IOException("resolveImageInternal returned null for uri: " + uri);
-        }
-        Bitmap bitmap = image.getBitmap();
-        image.setBitmap(Icon.scaleDownIfNecessary(bitmap, mMaxImageWidth, mMaxImageHeight));
-        return image;
+        return LocalImageResolver.resolveImage(uri, mContext, mMaxImageWidth, mMaxImageHeight);
     }
 
     @Override
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 05db67d..37d5da2 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
@@ -64,6 +64,7 @@
     private ImageView mWorkProfileImage;
     private View mAudiblyAlertedIcon;
     private View mFeedbackIcon;
+    private View mLeftIcon;
     private View mRightIcon;
 
     private boolean mIsLowPriority;
@@ -108,6 +109,7 @@
         mAppNameText = mView.findViewById(com.android.internal.R.id.app_name_text);
         mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
         mAltExpandTarget = mView.findViewById(com.android.internal.R.id.alternate_expand_target);
+        mLeftIcon = mView.findViewById(com.android.internal.R.id.left_icon);
         mRightIcon = mView.findViewById(com.android.internal.R.id.right_icon);
         mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
         mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
@@ -146,6 +148,9 @@
         updateCropToPaddingForImageViews();
         Notification notification = row.getEntry().getSbn().getNotification();
         mIcon.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
+        if (mLeftIcon != null) {
+            mLeftIcon.setClipToOutline(true);
+        }
         if (mRightIcon != null) {
             mRightIcon.setClipToOutline(true);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 885048d..ac3b6d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -82,9 +82,6 @@
     private ExpandableNotificationRow mTrackedHeadsUpRow;
     private float mAppearFraction;
 
-    /** Tracks the state from AlertingNotificationManager#hasNotifications() */
-    private boolean mHasAlertEntries;
-
     public AmbientState(
             Context context,
             @NonNull SectionProvider sectionProvider) {
@@ -368,21 +365,10 @@
         mPanelTracking = panelTracking;
     }
 
-    public boolean hasPulsingNotifications() {
-        return mPulsing && mHasAlertEntries;
-    }
-
     public void setPulsing(boolean hasPulsing) {
         mPulsing = hasPulsing;
     }
 
-    /**
-     * @return if we're pulsing in general
-     */
-    public boolean isPulsing() {
-        return mPulsing;
-    }
-
     public boolean isPulsing(NotificationEntry entry) {
         return mPulsing && entry.isAlerting();
     }
@@ -541,8 +527,4 @@
     public float getAppearFraction() {
         return mAppearFraction;
     }
-
-    public void setHasAlertEntries(boolean hasAlertEntries) {
-        mHasAlertEntries = hasAlertEntries;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index b04f94c..601fc19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -34,7 +34,7 @@
 import com.android.internal.widget.CachingIconView;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.NotificationHeaderUtil;
+import com.android.systemui.statusbar.NotificationGroupingUtil;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -94,7 +94,7 @@
     private NotificationViewWrapper mNotificationHeaderWrapper;
     private NotificationHeaderView mNotificationHeaderLowPriority;
     private NotificationViewWrapper mNotificationHeaderWrapperLowPriority;
-    private NotificationHeaderUtil mHeaderUtil;
+    private NotificationGroupingUtil mGroupingUtil;
     private ViewState mHeaderViewState;
     private int mClipBottomAmount;
     private boolean mIsLowPriority;
@@ -299,7 +299,7 @@
         row.setSystemChildExpanded(false);
         row.setUserLocked(false);
         if (!row.isRemoved()) {
-            mHeaderUtil.restoreNotificationHeader(row);
+            mGroupingUtil.restoreChildNotification(row);
         }
     }
 
@@ -341,7 +341,7 @@
         }
         recreateLowPriorityHeader(builder, isConversation);
         updateHeaderVisibility(false /* animate */);
-        updateChildrenHeaderAppearance();
+        updateChildrenAppearance();
     }
 
     /**
@@ -389,8 +389,11 @@
         }
     }
 
-    public void updateChildrenHeaderAppearance() {
-        mHeaderUtil.updateChildrenHeaderAppearance();
+    /**
+     * Update the appearance of the children to reduce redundancies.
+     */
+    public void updateChildrenAppearance() {
+        mGroupingUtil.updateChildrenAppearance();
     }
 
     public void updateGroupOverflow() {
@@ -861,7 +864,7 @@
 
     public void setContainingNotification(ExpandableNotificationRow parent) {
         mContainingNotification = parent;
-        mHeaderUtil = new NotificationHeaderUtil(mContainingNotification);
+        mGroupingUtil = new NotificationGroupingUtil(mContainingNotification);
     }
 
     public ExpandableNotificationRow getContainingNotification() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 1131a65..ba03a50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -31,175 +31,22 @@
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
 /**
- * Represents the bounds of a section of the notification shade and handles animation when the
- * bounds change.
+ * Represents the priority of a notification section and tracks first and last visible children.
  */
 public class NotificationSection {
     private @PriorityBucket int mBucket;
-    private View mOwningView;
-    private Rect mBounds = new Rect();
-    private Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
-    private Rect mStartAnimationRect = new Rect();
-    private Rect mEndAnimationRect = new Rect();
-    private ObjectAnimator mTopAnimator = null;
-    private ObjectAnimator mBottomAnimator = null;
     private ExpandableView mFirstVisibleChild;
     private ExpandableView mLastVisibleChild;
 
-    NotificationSection(View owningView, @PriorityBucket int bucket) {
-        mOwningView = owningView;
+    NotificationSection(@PriorityBucket int bucket) {
         mBucket = bucket;
     }
 
-    public void cancelAnimators() {
-        if (mBottomAnimator != null) {
-            mBottomAnimator.cancel();
-        }
-        if (mTopAnimator != null) {
-            mTopAnimator.cancel();
-        }
-    }
-
-    public Rect getCurrentBounds() {
-        return mCurrentBounds;
-    }
-
-    public Rect getBounds() {
-        return mBounds;
-    }
-
-    public boolean didBoundsChange() {
-        return !mCurrentBounds.equals(mBounds);
-    }
-
-    public boolean areBoundsAnimating() {
-        return mBottomAnimator != null || mTopAnimator != null;
-    }
-
     @PriorityBucket
     public int getBucket() {
         return mBucket;
     }
 
-    public void startBackgroundAnimation(boolean animateTop, boolean animateBottom) {
-        // Left and right bounds are always applied immediately.
-        mCurrentBounds.left = mBounds.left;
-        mCurrentBounds.right = mBounds.right;
-        startBottomAnimation(animateBottom);
-        startTopAnimation(animateTop);
-    }
-
-
-    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER)
-    private void startTopAnimation(boolean animate) {
-        int previousEndValue = mEndAnimationRect.top;
-        int newEndValue = mBounds.top;
-        ObjectAnimator previousAnimator = mTopAnimator;
-        if (previousAnimator != null && previousEndValue == newEndValue) {
-            return;
-        }
-        if (!animate) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                int previousStartValue = mStartAnimationRect.top;
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                values[0].setIntValues(previousStartValue, newEndValue);
-                mStartAnimationRect.top = previousStartValue;
-                mEndAnimationRect.top = newEndValue;
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                setBackgroundTop(newEndValue);
-                return;
-            }
-        }
-        if (previousAnimator != null) {
-            previousAnimator.cancel();
-        }
-        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop",
-                mCurrentBounds.top, newEndValue);
-        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
-        animator.setInterpolator(interpolator);
-        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mStartAnimationRect.top = -1;
-                mEndAnimationRect.top = -1;
-                mTopAnimator = null;
-            }
-        });
-        animator.start();
-        mStartAnimationRect.top = mCurrentBounds.top;
-        mEndAnimationRect.top = newEndValue;
-        mTopAnimator = animator;
-    }
-
-    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER)
-    private void startBottomAnimation(boolean animate) {
-        int previousStartValue = mStartAnimationRect.bottom;
-        int previousEndValue = mEndAnimationRect.bottom;
-        int newEndValue = mBounds.bottom;
-        ObjectAnimator previousAnimator = mBottomAnimator;
-        if (previousAnimator != null && previousEndValue == newEndValue) {
-            return;
-        }
-        if (!animate) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                values[0].setIntValues(previousStartValue, newEndValue);
-                mStartAnimationRect.bottom = previousStartValue;
-                mEndAnimationRect.bottom = newEndValue;
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                setBackgroundBottom(newEndValue);
-                return;
-            }
-        }
-        if (previousAnimator != null) {
-            previousAnimator.cancel();
-        }
-        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom",
-                mCurrentBounds.bottom, newEndValue);
-        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
-        animator.setInterpolator(interpolator);
-        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mStartAnimationRect.bottom = -1;
-                mEndAnimationRect.bottom = -1;
-                mBottomAnimator = null;
-            }
-        });
-        animator.start();
-        mStartAnimationRect.bottom = mCurrentBounds.bottom;
-        mEndAnimationRect.bottom = newEndValue;
-        mBottomAnimator = animator;
-    }
-
-    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW)
-    private void setBackgroundTop(int top) {
-        mCurrentBounds.top = top;
-        mOwningView.invalidate();
-    }
-
-    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW)
-    private void setBackgroundBottom(int bottom) {
-        mCurrentBounds.bottom = bottom;
-        mOwningView.invalidate();
-    }
-
     public ExpandableView getFirstVisibleChild() {
         return mFirstVisibleChild;
     }
@@ -219,93 +66,4 @@
         mLastVisibleChild = child;
         return changed;
     }
-
-    public void resetCurrentBounds() {
-        mCurrentBounds.set(mBounds);
-    }
-
-    /**
-     * Returns true if {@code top} is equal to the top of this section (if not currently animating)
-     * or where the top of this section will be when animation completes.
-     */
-    public boolean isTargetTop(int top) {
-        return (mTopAnimator == null && mCurrentBounds.top == top)
-                || (mTopAnimator != null && mEndAnimationRect.top == top);
-    }
-
-    /**
-     * Returns true if {@code bottom} is equal to the bottom of this section (if not currently
-     * animating) or where the bottom of this section will be when animation completes.
-     */
-    public boolean isTargetBottom(int bottom) {
-        return (mBottomAnimator == null && mCurrentBounds.bottom == bottom)
-                || (mBottomAnimator != null && mEndAnimationRect.bottom == bottom);
-    }
-
-    /**
-     * Update the bounds of this section based on it's views
-     *
-     * @param minTopPosition the minimum position that the top needs to have
-     * @param minBottomPosition the minimum position that the bottom needs to have
-     * @return the position of the new bottom
-     */
-    public int updateBounds(int minTopPosition, int minBottomPosition,
-            boolean shiftBackgroundWithFirst) {
-        int top = minTopPosition;
-        int bottom = minTopPosition;
-        ExpandableView firstView = getFirstVisibleChild();
-        if (firstView != null) {
-            // Round Y up to avoid seeing the background during animation
-            int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView));
-            // TODO: look into the already animating part
-            int newTop;
-            if (isTargetTop(finalTranslationY)) {
-                // we're ending up at the same location as we are now, let's just skip the
-                // animation
-                newTop = finalTranslationY;
-            } else {
-                newTop = (int) Math.ceil(firstView.getTranslationY());
-            }
-            top = Math.max(newTop, top);
-            if (firstView.showingPulsing()) {
-                // If we're pulsing, the notification can actually go below!
-                bottom = Math.max(bottom, finalTranslationY
-                        + ExpandableViewState.getFinalActualHeight(firstView));
-                if (shiftBackgroundWithFirst) {
-                    mBounds.left += Math.max(firstView.getTranslation(), 0);
-                    mBounds.right += Math.min(firstView.getTranslation(), 0);
-                }
-            }
-        }
-        top = Math.max(minTopPosition, top);
-        ExpandableView lastView = getLastVisibleChild();
-        if (lastView != null) {
-            float finalTranslationY = ViewState.getFinalTranslationY(lastView);
-            int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
-            // Round Y down to avoid seeing the background during animation
-            int finalBottom = (int) Math.floor(
-                    finalTranslationY + finalHeight - lastView.getClipBottomAmount());
-            int newBottom;
-            if (isTargetBottom(finalBottom)) {
-                // we're ending up at the same location as we are now, lets just skip the animation
-                newBottom = finalBottom;
-            } else {
-                newBottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
-                        - lastView.getClipBottomAmount());
-                // The background can never be lower than the end of the last view
-                minBottomPosition = (int) Math.min(
-                        lastView.getTranslationY() + lastView.getActualHeight(),
-                        minBottomPosition);
-            }
-            bottom = Math.max(bottom, Math.max(newBottom, minBottomPosition));
-        }
-        bottom = Math.max(top, bottom);
-        mBounds.top = top;
-        mBounds.bottom = bottom;
-        return bottom;
-    }
-
-    public boolean needsBackground() {
-        return mFirstVisibleChild != null && mBucket != BUCKET_MEDIA_CONTROLS;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 4f7e14b..36c5419 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -126,7 +126,7 @@
 
     fun createSectionsForBuckets(): Array<NotificationSection> =
             sectionsFeatureManager.getNotificationBuckets()
-                    .map { NotificationSection(parent, it) }
+                    .map { NotificationSection(it) }
                     .toTypedArray()
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 742e517..ba5f95e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -38,12 +38,9 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PointF;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.UserHandle;
@@ -73,7 +70,6 @@
 import android.widget.ScrollView;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.graphics.ColorUtils;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardSliceView;
@@ -158,8 +154,6 @@
     private ExpandHelper mExpandHelper;
     private NotificationSwipeHelper mSwipeHelper;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
-    private final Paint mBackgroundPaint = new Paint();
-    private final boolean mShouldDrawNotificationBackground;
     private boolean mHighPriorityBeforeSpeedBump;
     private boolean mDismissRtl;
 
@@ -258,7 +252,6 @@
     protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
     private boolean mDismissAllInProgress;
-    private boolean mFadeNotificationsOnDismiss;
     private FooterDismissListener mFooterDismissListener;
     private boolean mFlingAfterUpEvent;
 
@@ -328,10 +321,6 @@
         }
     };
     private NotificationSection[] mSections;
-    private boolean mAnimateNextBackgroundTop;
-    private boolean mAnimateNextBackgroundBottom;
-    private boolean mAnimateNextSectionBoundsChange;
-    private int mBgColor;
     private float mDimAmount;
     private ValueAnimator mDimAnimator;
     private ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
@@ -342,25 +331,14 @@
         }
     };
     private ValueAnimator.AnimatorUpdateListener mDimUpdateListener
-            = new ValueAnimator.AnimatorUpdateListener() {
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            setDimAmount((Float) animation.getAnimatedValue());
-        }
-    };
+            = animation -> setDimAmount((Float) animation.getAnimatedValue());
     protected ViewGroup mQsContainer;
     private boolean mContinuousShadowUpdate;
-    private boolean mContinuousBackgroundUpdate;
     private ViewTreeObserver.OnPreDrawListener mShadowUpdater
             = () -> {
                 updateViewShadows();
                 return true;
             };
-    private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater = () -> {
-                updateBackground();
-                return true;
-            };
     private Comparator<ExpandableView> mViewPositionComparator = (view, otherView) -> {
         float endY = view.getTranslationY() + view.getActualHeight();
         float otherEndY = otherView.getTranslationY() + otherView.getActualHeight();
@@ -379,7 +357,7 @@
             if (mAmbientState.isHiddenAtAll()) {
                 float xProgress = mHideXInterpolator.getInterpolation(
                         (1 - mLinearHideAmount) * mBackgroundXFactor);
-                outline.setRoundRect(mBackgroundAnimationRect,
+                outline.setRoundRect(mOutlineAnimationRect,
                         MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius,
                                 xProgress));
                 outline.setAlpha(1.0f - mAmbientState.getHideAmount());
@@ -388,7 +366,6 @@
             }
         }
     };
-    private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
     private boolean mPulsing;
     private boolean mScrollable;
     private View mForcedScroll;
@@ -422,7 +399,6 @@
     private boolean mInHeadsUpPinnedMode;
     private boolean mHeadsUpAnimatingAway;
     private int mStatusBarState;
-    private int mCachedBackgroundColor;
     private boolean mHeadsUpGoingAwayAnimationsAllowed = true;
     private Runnable mReflingAndAnimateScroll = () -> {
         if (ANCHOR_SCROLLING) {
@@ -432,7 +408,7 @@
     };
     private int mCornerRadius;
     private int mSidePaddings;
-    private final Rect mBackgroundAnimationRect = new Rect();
+    private final Rect mOutlineAnimationRect = new Rect();
     private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
     private int mHeadsUpInset;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
@@ -452,7 +428,6 @@
 
     private final NotificationSectionsManager mSectionsManager;
     private ForegroundServiceDungeonView mFgsSectionView;
-    private boolean mAnimateBottomOnLayout;
     private float mLastSentAppear;
     private float mLastSentExpandedHeight;
     private boolean mWillExpand;
@@ -463,7 +438,6 @@
 
     private boolean mKeyguardMediaControllorVisible;
     private NotificationEntry mTopHeadsUpEntry;
-    private long mNumHeadsUp;
     private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
 
     private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
@@ -530,7 +504,6 @@
         mSections = mSectionsManager.createSectionsForBuckets();
 
         mAmbientState = new AmbientState(context, mSectionsManager);
-        mBgColor = context.getColor(R.color.notification_shade_background_color);
         int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
         mExpandHelper = new ExpandHelper(getContext(), mExpandHelperCallback,
@@ -539,13 +512,9 @@
         mExpandHelper.setScrollAdapter(mScrollAdapter);
 
         mStackScrollAlgorithm = createStackScrollAlgorithm(context);
-        mShouldDrawNotificationBackground =
-                res.getBoolean(R.bool.config_drawNotificationBackground);
         setOutlineProvider(mOutlineProvider);
 
-        boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
-        setWillNotDraw(!willDraw);
-        mBackgroundPaint.setAntiAlias(true);
+        setWillNotDraw(!DEBUG);
         if (DEBUG) {
             mDebugPaint = new Paint();
             mDebugPaint.setColor(0xffff0000);
@@ -590,7 +559,7 @@
      * @return the height at which we will wake up when pulsing
      */
     public float getWakeUpHeight() {
-        ExpandableView firstChild = getFirstChildWithBackground();
+        ExpandableView firstChild = getFirstExpandableView();
         if (firstChild != null) {
             if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
                 return firstChild.getHeadsUpHeightWithoutHeader();
@@ -641,22 +610,11 @@
     }
 
     void updateBgColor() {
-        mBgColor = mContext.getColor(R.color.notification_shade_background_color);
-        updateBackgroundDimming();
         mShelf.onUiModeChanged();
     }
 
     @ShadeViewRefactor(RefactorComponent.DECORATOR)
     protected void onDraw(Canvas canvas) {
-        if (mShouldDrawNotificationBackground
-                && (mSections[0].getCurrentBounds().top
-                < mSections[mSections.length - 1].getCurrentBounds().bottom
-                || mAmbientState.isDozing())) {
-            drawBackground(canvas);
-        } else if (mInHeadsUpPinnedMode || mHeadsUpAnimatingAway) {
-            drawHeadsUpBackground(canvas);
-        }
-
         if (DEBUG) {
             int y = mTopPadding;
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -691,160 +649,6 @@
         }
     }
 
-    @ShadeViewRefactor(RefactorComponent.DECORATOR)
-    private void drawBackground(Canvas canvas) {
-        int lockScreenLeft = mSidePaddings;
-        int lockScreenRight = getWidth() - mSidePaddings;
-        int lockScreenTop = mSections[0].getCurrentBounds().top;
-        int lockScreenBottom = mSections[mSections.length - 1].getCurrentBounds().bottom;
-        int hiddenLeft = getWidth() / 2;
-        int hiddenTop = mTopPadding;
-
-        float yProgress = 1 - mInterpolatedHideAmount;
-        float xProgress = mHideXInterpolator.getInterpolation(
-                (1 - mLinearHideAmount) * mBackgroundXFactor);
-
-        int left = (int) MathUtils.lerp(hiddenLeft, lockScreenLeft, xProgress);
-        int right = (int) MathUtils.lerp(hiddenLeft, lockScreenRight, xProgress);
-        int top = (int) MathUtils.lerp(hiddenTop, lockScreenTop, yProgress);
-        int bottom = (int) MathUtils.lerp(hiddenTop, lockScreenBottom, yProgress);
-        mBackgroundAnimationRect.set(
-                left,
-                top,
-                right,
-                bottom);
-
-        int backgroundTopAnimationOffset = top - lockScreenTop;
-        // TODO(kprevas): this may not be necessary any more since we don't display the shelf in AOD
-        boolean anySectionHasVisibleChild = false;
-        for (NotificationSection section : mSections) {
-            if (section.needsBackground()) {
-                anySectionHasVisibleChild = true;
-                break;
-            }
-        }
-        boolean shouldDrawBackground;
-        if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
-            shouldDrawBackground = isPulseExpanding();
-        } else {
-            shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
-        }
-        if (shouldDrawBackground) {
-            drawBackgroundRects(canvas, left, right, top, backgroundTopAnimationOffset);
-        }
-
-        updateClipping();
-    }
-
-    /**
-     * Draws round rects for each background section.
-     *
-     * We want to draw a round rect for each background section as defined by {@link #mSections}.
-     * However, if two sections are directly adjacent with no gap between them (e.g. on the
-     * lockscreen where the shelf can appear directly below the high priority section, or while
-     * scrolling the shade so that the top of the shelf is right at the bottom of the high priority
-     * section), we don't want to round the adjacent corners.
-     *
-     * Since {@link Canvas} doesn't provide a way to draw a half-rounded rect, this means that we
-     * need to coalesce the backgrounds for adjacent sections and draw them as a single round rect.
-     * This method tracks the top of each rect we need to draw, then iterates through the visible
-     * sections.  If a section is not adjacent to the previous section, we draw the previous rect
-     * behind the sections we've accumulated up to that point, then start a new rect at the top of
-     * the current section.  When we're done iterating we will always have one rect left to draw.
-     */
-    private void drawBackgroundRects(Canvas canvas, int left, int right, int top,
-            int animationYOffset) {
-        int backgroundRectTop = top;
-        int lastSectionBottom =
-                mSections[0].getCurrentBounds().bottom + animationYOffset;
-        int currentLeft = left;
-        int currentRight = right;
-        boolean first = true;
-        for (NotificationSection section : mSections) {
-            if (!section.needsBackground()) {
-                continue;
-            }
-            int sectionTop = section.getCurrentBounds().top + animationYOffset;
-            int ownLeft = Math.min(Math.max(left, section.getCurrentBounds().left), right);
-            int ownRight = Math.max(Math.min(right, section.getCurrentBounds().right), ownLeft);
-            // If sections are directly adjacent to each other, we don't want to draw them
-            // as separate roundrects, as the rounded corners right next to each other look
-            // bad.
-            if (sectionTop - lastSectionBottom > DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX
-                    || ((currentLeft != ownLeft || currentRight != ownRight) && !first)) {
-                canvas.drawRoundRect(currentLeft,
-                        backgroundRectTop,
-                        currentRight,
-                        lastSectionBottom,
-                        mCornerRadius, mCornerRadius, mBackgroundPaint);
-                backgroundRectTop = sectionTop;
-            }
-            currentLeft = ownLeft;
-            currentRight = ownRight;
-            lastSectionBottom =
-                    section.getCurrentBounds().bottom + animationYOffset;
-            first = false;
-        }
-        canvas.drawRoundRect(currentLeft,
-                backgroundRectTop,
-                currentRight,
-                lastSectionBottom,
-                mCornerRadius, mCornerRadius, mBackgroundPaint);
-    }
-
-    private void drawHeadsUpBackground(Canvas canvas) {
-        int left = mSidePaddings;
-        int right = getWidth() - mSidePaddings;
-
-        float top = getHeight();
-        float bottom = 0;
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE
-                    && child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if ((row.isPinned() || row.isHeadsUpAnimatingAway()) && row.getTranslation() < 0
-                        && row.getProvider().shouldShowGutsOnSnapOpen()) {
-                    top = Math.min(top, row.getTranslationY());
-                    bottom = Math.max(bottom, row.getTranslationY() + row.getActualHeight());
-                }
-            }
-        }
-
-        if (top < bottom) {
-            canvas.drawRoundRect(
-                    left, top, right, bottom,
-                    mCornerRadius, mCornerRadius, mBackgroundPaint);
-        }
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    void updateBackgroundDimming() {
-        // No need to update the background color if it's not being drawn.
-        if (!mShouldDrawNotificationBackground) {
-            return;
-        }
-        final boolean newFlowHideShelf = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.SHOW_NEW_NOTIF_DISMISS, 1 /* on by default */) == 1;
-        if (newFlowHideShelf) {
-            mBackgroundPaint.setColor(Color.TRANSPARENT);
-            invalidate();
-            return;
-        }
-        // Interpolate between semi-transparent notification panel background color
-        // and white AOD separator.
-        float colorInterpolation = MathUtils.smoothStep(0.4f /* start */, 1f /* end */,
-                mLinearHideAmount);
-        int color = ColorUtils.blendARGB(mBgColor, Color.WHITE, colorInterpolation);
-
-        if (mCachedBackgroundColor != color) {
-            mCachedBackgroundColor = color;
-            mBackgroundPaint.setColor(color);
-            invalidate();
-        }
-    }
-
     private void reinitView() {
         initView(getContext(), mKeyguardBypassEnabledProvider, mSwipeHelper);
     }
@@ -979,7 +783,7 @@
         updateContentHeight();
         clampScrollPosition();
         requestChildrenUpdate();
-        updateFirstAndLastBackgroundViews();
+        updateFirstAndLastExpandableView();
         updateAlgorithmLayoutMinHeight();
         updateOwnTranslationZ();
     }
@@ -1050,9 +854,6 @@
     private void onPreDrawDuringAnimation() {
         mShelf.updateAppearance();
         updateClippingToTopRoundedCorner();
-        if (!mNeedsAnimation && !mChildrenUpdateRequested) {
-            updateBackground();
-        }
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -2369,131 +2170,6 @@
         }
     }
 
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void updateBackground() {
-        // No need to update the background color if it's not being drawn.
-        if (!mShouldDrawNotificationBackground) {
-            return;
-        }
-
-        updateBackgroundBounds();
-        if (didSectionBoundsChange()) {
-            boolean animate = mAnimateNextSectionBoundsChange || mAnimateNextBackgroundTop
-                    || mAnimateNextBackgroundBottom || areSectionBoundsAnimating();
-            if (!isExpanded()) {
-                abortBackgroundAnimators();
-                animate = false;
-            }
-            if (animate) {
-                startBackgroundAnimation();
-            } else {
-                for (NotificationSection section : mSections) {
-                    section.resetCurrentBounds();
-                }
-                invalidate();
-            }
-        } else {
-            abortBackgroundAnimators();
-        }
-        mAnimateNextBackgroundTop = false;
-        mAnimateNextBackgroundBottom = false;
-        mAnimateNextSectionBoundsChange = false;
-    }
-
-    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private void abortBackgroundAnimators() {
-        for (NotificationSection section : mSections) {
-            section.cancelAnimators();
-        }
-    }
-
-    private boolean didSectionBoundsChange() {
-        for (NotificationSection section : mSections) {
-            if (section.didBoundsChange()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private boolean areSectionBoundsAnimating() {
-        for (NotificationSection section : mSections) {
-            if (section.areBoundsAnimating()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private void startBackgroundAnimation() {
-        // TODO(kprevas): do we still need separate fields for top/bottom?
-        // or can each section manage its own animation state?
-        NotificationSection firstVisibleSection = getFirstVisibleSection();
-        NotificationSection lastVisibleSection = getLastVisibleSection();
-        for (NotificationSection section : mSections) {
-            section.startBackgroundAnimation(
-                    section == firstVisibleSection
-                            ? mAnimateNextBackgroundTop
-                            : mAnimateNextSectionBoundsChange,
-                    section == lastVisibleSection
-                            ? mAnimateNextBackgroundBottom
-                            : mAnimateNextSectionBoundsChange);
-        }
-    }
-
-    /**
-     * Update the background bounds to the new desired bounds
-     */
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void updateBackgroundBounds() {
-        int left = mSidePaddings;
-        int right = getWidth() - mSidePaddings;
-        for (NotificationSection section : mSections) {
-            section.getBounds().left = left;
-            section.getBounds().right = right;
-        }
-
-        if (!mIsExpanded) {
-            for (NotificationSection section : mSections) {
-                section.getBounds().top = 0;
-                section.getBounds().bottom = 0;
-            }
-            return;
-        }
-        int minTopPosition;
-        NotificationSection lastSection = getLastVisibleSection();
-        boolean onKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
-        if (!onKeyguard) {
-            minTopPosition = (int) (mTopPadding + mStackTranslation);
-        } else if (lastSection == null) {
-            minTopPosition = mTopPadding;
-        } else {
-            // The first sections could be empty while there could still be elements in later
-            // sections. The position of these first few sections is determined by the position of
-            // the first visible section.
-            NotificationSection firstVisibleSection = getFirstVisibleSection();
-            firstVisibleSection.updateBounds(0 /* minTopPosition*/, 0 /* minBottomPosition */,
-                    false /* shiftPulsingWithFirst */);
-            minTopPosition = firstVisibleSection.getBounds().top;
-        }
-        boolean shiftPulsingWithFirst = mNumHeadsUp <= 1
-                && (mAmbientState.isDozing()
-                        || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
-        for (NotificationSection section : mSections) {
-            int minBottomPosition = minTopPosition;
-            if (section == lastSection) {
-                // We need to make sure the section goes all the way to the shelf
-                minBottomPosition = (int) (ViewState.getFinalTranslationY(mShelf)
-                        + mShelf.getIntrinsicHeight());
-            }
-            minTopPosition = section.updateBounds(minTopPosition, minBottomPosition,
-                    shiftPulsingWithFirst);
-            shiftPulsingWithFirst = false;
-        }
-    }
-
     private NotificationSection getFirstVisibleSection() {
         for (NotificationSection section : mSections) {
             if (section.getFirstVisibleChild() != null) {
@@ -2514,7 +2190,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    private ExpandableView getLastChildWithBackground() {
+    private ExpandableView getLastExpandableView() {
         int childCount = getChildCount();
         for (int i = childCount - 1; i >= 0; i--) {
             ExpandableView child = (ExpandableView) getChildAt(i);
@@ -2527,7 +2203,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    private ExpandableView getFirstChildWithBackground() {
+    private ExpandableView getFirstExpandableView() {
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
@@ -2540,7 +2216,7 @@
     }
 
     //TODO: We shouldn't have to generate this list every time
-    private List<ExpandableView> getChildrenWithBackground() {
+    private List<ExpandableView> getExpandableViewList() {
         ArrayList<ExpandableView> children = new ArrayList<>();
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -3078,32 +2754,13 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private void updateFirstAndLastBackgroundViews() {
-        NotificationSection firstSection = getFirstVisibleSection();
-        NotificationSection lastSection = getLastVisibleSection();
-        ExpandableView previousFirstChild =
-                firstSection == null ? null : firstSection.getFirstVisibleChild();
-        ExpandableView previousLastChild =
-                lastSection == null ? null : lastSection.getLastVisibleChild();
-
-        ExpandableView firstChild = getFirstChildWithBackground();
-        ExpandableView lastChild = getLastChildWithBackground();
-        boolean sectionViewsChanged = mSectionsManager.updateFirstAndLastViewsForAllSections(
-                mSections, getChildrenWithBackground());
-
-        if (mAnimationsEnabled && mIsExpanded) {
-            mAnimateNextBackgroundTop = firstChild != previousFirstChild;
-            mAnimateNextBackgroundBottom = lastChild != previousLastChild || mAnimateBottomOnLayout;
-            mAnimateNextSectionBoundsChange = sectionViewsChanged;
-        } else {
-            mAnimateNextBackgroundTop = false;
-            mAnimateNextBackgroundBottom = false;
-            mAnimateNextSectionBoundsChange = false;
-        }
+    private void updateFirstAndLastExpandableView() {
+        ExpandableView lastChild = getLastExpandableView();
+        mSectionsManager.updateFirstAndLastViewsForAllSections(
+                mSections, getExpandableViewList());
         mAmbientState.setLastVisibleBackgroundChild(lastChild);
         // TODO: Refactor SectionManager and put the RoundnessManager there.
         mController.getNoticationRoundessManager().updateRoundedChildren(mSections);
-        mAnimateBottomOnLayout = false;
         invalidate();
     }
 
@@ -3265,7 +2922,6 @@
             setAnimationRunning(true);
             mStateAnimator.startAnimationForEvents(mAnimationEvents, mGoToFullShadeDelay);
             mAnimationEvents.clear();
-            updateBackground();
             updateViewShadows();
             updateClippingToTopRoundedCorner();
         } else {
@@ -4350,7 +4006,6 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void setDimAmount(float dimAmount) {
         mDimAmount = dimAmount;
-        updateBackgroundDimming();
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4419,7 +4074,6 @@
         }
         runAnimationFinishedRunnables();
         setAnimationRunning(false);
-        updateBackground();
         updateViewShadows();
         updateClippingToTopRoundedCorner();
     }
@@ -4554,7 +4208,6 @@
             invalidateOutline();
         }
         updateAlgorithmHeightAndPadding();
-        updateBackgroundDimming();
         requestChildrenUpdate();
         updateOwnTranslationZ();
     }
@@ -5435,7 +5088,6 @@
      */
     public void setDozeAmount(float dozeAmount) {
         mAmbientState.setDozeAmount(dozeAmount);
-        updateContinuousBackgroundDrawing();
         requestChildrenUpdate();
     }
 
@@ -5473,7 +5125,6 @@
     }
 
     void setAnimateBottomOnLayout(boolean animateBottomOnLayout) {
-        mAnimateBottomOnLayout = animateBottomOnLayout;
     }
 
     public void setOnPulseHeightChangedListener(Runnable listener) {
@@ -5506,25 +5157,14 @@
 
     void onSwipeBegin() {
         requestDisallowInterceptTouchEvent(true);
-        updateFirstAndLastBackgroundViews();
         updateContinuousShadowDrawing();
-        updateContinuousBackgroundDrawing();
         requestChildrenUpdate();
     }
 
-    void onSwipeEnd() {
-        updateFirstAndLastBackgroundViews();
-    }
-
     void setTopHeadsUpEntry(NotificationEntry topEntry) {
         mTopHeadsUpEntry = topEntry;
     }
 
-    void setNumHeadsUp(long numHeadsUp) {
-        mNumHeadsUp = numHeadsUp;
-        mAmbientState.setHasAlertEntries(numHeadsUp > 0);
-    }
-
     public boolean getIsExpanded() {
         return mIsExpanded;
     }
@@ -5639,27 +5279,6 @@
         mSectionsManager.updateSectionBoundaries(reason);
     }
 
-    boolean isSilkDismissEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.SHOW_NEW_NOTIF_DISMISS, 1 /* enabled by default */) == 1;
-    }
-
-    void updateContinuousBackgroundDrawing() {
-        if (isSilkDismissEnabled()) {
-            return;
-        }
-        boolean continuousBackground = !mAmbientState.isFullyAwake()
-                && mSwipeHelper.isSwiping();
-        if (continuousBackground != mContinuousBackgroundUpdate) {
-            mContinuousBackgroundUpdate = continuousBackground;
-            if (continuousBackground) {
-                getViewTreeObserver().addOnPreDrawListener(mBackgroundUpdater);
-            } else {
-                getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
-            }
-        }
-    }
-
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     void updateContinuousShadowDrawing() {
         boolean continuousShadowUpdate = mAnimationRunning
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 006d8da..abbbbb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -60,10 +60,10 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.media.KeyguardMediaController;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -143,7 +143,7 @@
     private final ConfigurationController mConfigurationController;
     private final ZenModeController mZenModeController;
     private final MetricsLogger mMetricsLogger;
-    private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
     private final Resources mResources;
     private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
     private final ScrimController mScrimController;
@@ -361,7 +361,7 @@
 
                 @Override
                 public void onDragCancelled(View v) {
-                    mFalsingManager.onNotificationStopDismissing();
+                    mFalsingCollector.onNotificationStopDismissing();
                 }
 
                 /**
@@ -394,7 +394,6 @@
                     if (mView.getDismissAllInProgress()) {
                         return;
                     }
-                    mView.onSwipeEnd();
                     if (view instanceof ExpandableNotificationRow) {
                         ExpandableNotificationRow row = (ExpandableNotificationRow) view;
                         if (row.isHeadsUp()) {
@@ -405,8 +404,8 @@
                     }
 
                     mView.addSwipedOutView(view);
-                    mFalsingManager.onNotificationDismissed();
-                    if (mFalsingManager.shouldEnforceBouncer()) {
+                    mFalsingCollector.onNotificationDismissed();
+                    if (mFalsingCollector.shouldEnforceBouncer()) {
                         mStatusBar.executeRunnableDismissingKeyguard(
                                 null,
                                 null /* cancelAction */,
@@ -448,13 +447,12 @@
 
                 @Override
                 public void onBeginDrag(View v) {
-                    mFalsingManager.onNotificationStartDismissing();
+                    mFalsingCollector.onNotificationStartDismissing();
                     mView.onSwipeBegin();
                 }
 
                 @Override
                 public void onChildSnappedBack(View animView, float targetLeft) {
-                    mView.onSwipeEnd();
                     if (animView instanceof ExpandableNotificationRow) {
                         ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
                         if (row.isPinned() && !canChildBeDismissed(row)
@@ -518,9 +516,7 @@
 
                 @Override
                 public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-                    long numEntries = mHeadsUpManager.getAllEntries().count();
                     NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
-                    mView.setNumHeadsUp(numEntries);
                     mView.setTopHeadsUpEntry(topEntry);
                     mNotificationRoundnessManager.updateView(entry.getRow(), false /* animate */);
                 }
@@ -550,7 +546,7 @@
             SysuiColorExtractor colorExtractor,
             NotificationLockscreenUserManager lockscreenUserManager,
             MetricsLogger metricsLogger,
-            FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             @Main Resources resources,
             NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
             StatusBar statusBar,
@@ -584,7 +580,7 @@
         mColorExtractor = colorExtractor;
         mLockscreenUserManager = lockscreenUserManager;
         mMetricsLogger = metricsLogger;
-        mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
         mResources = resources;
         mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
         mStatusBar = statusBar;
@@ -665,8 +661,6 @@
         mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed);
         mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
 
-        mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
-
         mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
 
         mFadeNotificationsOnDismiss =  // TODO: this should probably be injected directly
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 80cb289..9854f54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -39,9 +39,9 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -65,7 +65,7 @@
     protected final Context mContext;
     protected final ViewMediatorCallback mCallback;
     protected final ViewGroup mContainer;
-    private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
     private final DismissCallbackRegistry mDismissCallbackRegistry;
     private final Handler mHandler;
     private final List<BouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>();
@@ -100,7 +100,7 @@
 
     private KeyguardBouncer(Context context, ViewMediatorCallback callback,
             ViewGroup container,
-            DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
+            DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
             BouncerExpansionCallback expansionCallback,
             KeyguardStateController keyguardStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -111,7 +111,7 @@
         mCallback = callback;
         mContainer = container;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
-        mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
         mDismissCallbackRegistry = dismissCallbackRegistry;
         mHandler = handler;
         mKeyguardStateController = keyguardStateController;
@@ -203,7 +203,7 @@
      * will never be notified and its internal state will be out of sync.
      */
     private void onFullyShown() {
-        mFalsingManager.onBouncerShown();
+        mFalsingCollector.onBouncerShown();
         if (mKeyguardViewController == null) {
             Log.wtf(TAG, "onFullyShown when view was null");
         } else {
@@ -223,7 +223,7 @@
         if (mRoot != null) {
             mRoot.setVisibility(View.INVISIBLE);
         }
-        mFalsingManager.onBouncerHidden();
+        mFalsingCollector.onBouncerHidden();
         DejankUtils.postAfterTraversal(mResetRunnable);
     }
 
@@ -290,7 +290,7 @@
             mDismissCallbackRegistry.notifyDismissCancelled();
         }
         mIsScrimmed = false;
-        mFalsingManager.onBouncerHidden();
+        mFalsingCollector.onBouncerHidden();
         mCallback.onBouncerVisiblityChanged(false /* shown */);
         cancelShowRunnable();
         if (mKeyguardViewController != null) {
@@ -327,7 +327,7 @@
     public void reset() {
         cancelShowRunnable();
         inflateView();
-        mFalsingManager.onBouncerHidden();
+        mFalsingCollector.onBouncerHidden();
     }
 
     public void onScreenTurnedOff() {
@@ -541,7 +541,7 @@
         private final Context mContext;
         private final ViewMediatorCallback mCallback;
         private final DismissCallbackRegistry mDismissCallbackRegistry;
-        private final FalsingManager mFalsingManager;
+        private final FalsingCollector mFalsingCollector;
         private final KeyguardStateController mKeyguardStateController;
         private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
         private final KeyguardBypassController mKeyguardBypassController;
@@ -551,7 +551,7 @@
 
         @Inject
         public Factory(Context context, ViewMediatorCallback callback,
-                DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
+                DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
                 KeyguardStateController keyguardStateController,
                 KeyguardUpdateMonitor keyguardUpdateMonitor,
                 KeyguardBypassController keyguardBypassController, Handler handler,
@@ -560,7 +560,7 @@
             mContext = context;
             mCallback = callback;
             mDismissCallbackRegistry = dismissCallbackRegistry;
-            mFalsingManager = falsingManager;
+            mFalsingCollector = falsingCollector;
             mKeyguardStateController = keyguardStateController;
             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
             mKeyguardBypassController = keyguardBypassController;
@@ -572,7 +572,7 @@
         public KeyguardBouncer create(@RootView ViewGroup container,
                 BouncerExpansionCallback expansionCallback) {
             return new KeyguardBouncer(mContext, mCallback, container,
-                    mDismissCallbackRegistry, mFalsingManager, expansionCallback,
+                    mDismissCallbackRegistry, mFalsingCollector, expansionCallback,
                     mKeyguardStateController, mKeyguardUpdateMonitor,
                     mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
                     mKeyguardBouncerComponentFactory);
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 7508dcb..1a2d1cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInScale;
 import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate;
 
 import android.content.res.Resources;
@@ -184,6 +185,7 @@
         result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
                 : getClockY(1.0f) + mKeyguardStatusHeight;
         result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
+        result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount);
     }
 
     /**
@@ -304,6 +306,11 @@
         public float clockAlpha;
 
         /**
+         * Amount to scale the large clock (0.0 - 1.0)
+         */
+        public float clockScale;
+
+        /**
          * The top padding of the stack scroller, in pixels.
          */
         public int stackScrollerPadding;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 6b88811..c67e8fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -68,6 +68,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.DisabledUdfpsController;
 import com.android.keyguard.KeyguardClockSwitchController;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
@@ -79,6 +80,7 @@
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeLog;
@@ -255,7 +257,25 @@
                     mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
                     mDelayShowingKeyguardStatusBar = false;
                 }
-            };
+
+                @Override
+                public void onKeyguardVisibilityChanged(boolean showing) {
+                    if (mDisabledUdfpsController == null
+                            && mAuthController.getUdfpsRegion() != null
+                            && mAuthController.isUdfpsEnrolled(
+                                   KeyguardUpdateMonitor.getCurrentUser())) {
+                        LayoutInflater.from(mView.getContext())
+                                .inflate(R.layout.disabled_udfps_view, mView);
+                        mDisabledUdfpsController = new DisabledUdfpsController(
+                                mView.findViewById(R.id.disabled_udfps_view),
+                                mStatusBarStateController,
+                                mUpdateMonitor,
+                                mAuthController,
+                                mStatusBarKeyguardViewManager);
+                        mDisabledUdfpsController.init();
+                    }
+                }
+    };
 
     private final InjectionInflationController mInjectionInflationController;
     private final PowerManager mPowerManager;
@@ -283,6 +303,7 @@
     private QS mQs;
     private FrameLayout mQsFrame;
     private KeyguardStatusViewController mKeyguardStatusViewController;
+    private DisabledUdfpsController mDisabledUdfpsController;
     private View mQsNavbarScrim;
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
     private boolean mAnimateNextPositionUpdate;
@@ -364,7 +385,8 @@
     private boolean mHeadsUpAnimatingAway;
     private boolean mLaunchingAffordance;
     private boolean mAffordanceHasPreview;
-    private FalsingManager mFalsingManager;
+    private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
     private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
 
     private Runnable mHeadsUpExistenceChangedRunnable = () -> {
@@ -502,7 +524,7 @@
             NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
             DynamicPrivacyController dynamicPrivacyController,
             KeyguardBypassController bypassController, FalsingManager falsingManager,
-            ShadeController shadeController,
+            FalsingCollector falsingCollector, ShadeController shadeController,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             NotificationEntryManager notificationEntryManager,
             KeyguardStateController keyguardStateController,
@@ -543,6 +565,7 @@
         mView.setWillNotDraw(!DEBUG);
         mInjectionInflationController = injectionInflationController;
         mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
         mPowerManager = powerManager;
         mWakeUpCoordinator = coordinator;
         mAccessibilityManager = accessibilityManager;
@@ -885,7 +908,8 @@
                     mUpdateMonitor.isUdfpsEnrolled());
             mClockPositionAlgorithm.run(mClockPositionResult);
             mKeyguardStatusViewController.updatePosition(
-                    mClockPositionResult.clockX, mClockPositionResult.clockY, animateClock);
+                    mClockPositionResult.clockX, mClockPositionResult.clockY,
+                    mClockPositionResult.clockScale, animateClock);
             updateNotificationTranslucency();
             updateClock();
             stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded;
@@ -1426,7 +1450,7 @@
     private void handleQsDown(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN && shouldQuickSettingsIntercept(
                 event.getX(), event.getY(), -1)) {
-            mFalsingManager.onQsDown();
+            mFalsingCollector.onQsDown();
             mQsTracking = true;
             onQsExpansionStarted();
             mInitialHeightOnTouch = mQsExpansionHeight;
@@ -1606,7 +1630,7 @@
             mQsExpanded = expanded;
             updateQsState();
             requestPanelHeightUpdate();
-            mFalsingManager.setQsExpanded(expanded);
+            mFalsingCollector.setQsExpanded(expanded);
             mStatusBar.setQsExpanded(expanded);
             mNotificationContainerParent.setQsExpanded(expanded);
             mPulseExpansionHandler.setQsExpanded(expanded);
@@ -1743,7 +1767,7 @@
         }
 
         if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded
-                && mFalsingManager.shouldEnforceBouncer()) {
+                && mFalsingCollector.shouldEnforceBouncer()) {
             mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
                     false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
         }
@@ -2404,7 +2428,7 @@
 
     @Override
     protected void onTrackingStarted() {
-        mFalsingManager.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
+        mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
         super.onTrackingStarted();
         if (mQsFullyExpanded) {
             mQsExpandImmediate = true;
@@ -2418,7 +2442,7 @@
 
     @Override
     protected void onTrackingStopped(boolean expand) {
-        mFalsingManager.onTrackingStopped();
+        mFalsingCollector.onTrackingStopped();
         super.onTrackingStopped(expand);
         if (expand) {
             mNotificationStackScrollLayoutController.setOverScrolledPixels(0.0f, true /* onTop */,
@@ -3041,6 +3065,9 @@
         if (mKeyguardStatusBar != null) {
             mKeyguardStatusBar.dump(fd, pw, args);
         }
+        if (mDisabledUdfpsController != null) {
+            mDisabledUdfpsController.dump(fd, pw, args);
+        }
     }
 
     public boolean hasActiveClearableNotifications() {
@@ -3365,8 +3392,8 @@
             if (start) {
                 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp);
                 mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_DIALER);
-                mFalsingManager.onLeftAffordanceOn();
-                if (mFalsingManager.shouldEnforceBouncer()) {
+                mFalsingCollector.onLeftAffordanceOn();
+                if (mFalsingCollector.shouldEnforceBouncer()) {
                     mStatusBar.executeRunnableDismissingKeyguard(
                             () -> mKeyguardBottomArea.launchLeftAffordance(), null,
                             true /* dismissShade */, false /* afterKeyguardGone */,
@@ -3381,8 +3408,8 @@
                             MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp);
                     mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_CAMERA);
                 }
-                mFalsingManager.onCameraOn();
-                if (mFalsingManager.shouldEnforceBouncer()) {
+                mFalsingCollector.onCameraOn();
+                if (mFalsingCollector.shouldEnforceBouncer()) {
                     mStatusBar.executeRunnableDismissingKeyguard(
                             () -> mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource), null,
                             true /* dismissShade */, false /* afterKeyguardGone */,
@@ -3413,7 +3440,7 @@
 
         @Override
         public void onSwipingStarted(boolean rightIcon) {
-            mFalsingManager.onAffordanceSwipingStarted(rightIcon);
+            mFalsingCollector.onAffordanceSwipingStarted(rightIcon);
             boolean
                     camera =
                     mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? !rightIcon
@@ -3428,7 +3455,7 @@
 
         @Override
         public void onSwipingAborted() {
-            mFalsingManager.onAffordanceSwipingAborted();
+            mFalsingCollector.onAffordanceSwipingAborted();
             mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 3db3ab5..ba4fbb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.plugins.FalsingManager;
@@ -73,6 +74,7 @@
     private final KeyguardBypassController mBypassController;
     private final PluginManager mPluginManager;
     private final FalsingManager mFalsingManager;
+    private final FalsingCollector mFalsingCollector;
     private final TunerService mTunerService;
     private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     private final NotificationEntryManager mNotificationEntryManager;
@@ -118,6 +120,7 @@
             DynamicPrivacyController dynamicPrivacyController,
             KeyguardBypassController bypassController,
             FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             PluginManager pluginManager,
             TunerService tunerService,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
@@ -140,6 +143,7 @@
         mDynamicPrivacyController = dynamicPrivacyController;
         mBypassController = bypassController;
         mFalsingManager = falsingManager;
+        mFalsingCollector = falsingCollector;
         mPluginManager = pluginManager;
         mTunerService = tunerService;
         mNotificationLockscreenUserManager = notificationLockscreenUserManager;
@@ -234,7 +238,7 @@
                 if (mTouchCancelled || mExpandAnimationRunning || mExpandAnimationPending) {
                     return false;
                 }
-                mFalsingManager.onTouchEvent(ev, mView.getWidth(), mView.getHeight());
+                mFalsingCollector.onTouchEvent(ev, mView.getWidth(), mView.getHeight());
                 mGestureDetector.onTouchEvent(ev);
                 if (mBrightnessMirror != null
                         && mBrightnessMirror.getVisibility() == View.VISIBLE) {
@@ -394,7 +398,7 @@
         setDragDownHelper(
                 new DragDownHelper(
                         mView.getContext(), mView, expandHelperCallback,
-                        dragDownCallback, mFalsingManager));
+                        dragDownCallback, mFalsingManager, mFalsingCollector));
 
         mDepthController.setRoot(mView);
         mNotificationPanelViewController.addExpansionListener(mDepthController);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e6ac7dc..c8c5a63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -147,6 +147,7 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.charging.WirelessChargingAnimation;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.demomode.DemoMode;
@@ -384,6 +385,7 @@
     private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
     private final DynamicPrivacyController mDynamicPrivacyController;
     private final BypassHeadsUpNotifier mBypassHeadsUpNotifier;
+    private final FalsingCollector mFalsingCollector;
     private final FalsingManager mFalsingManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final ConfigurationController mConfigurationController;
@@ -692,6 +694,7 @@
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
             FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
@@ -772,6 +775,7 @@
         mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
         mDynamicPrivacyController = dynamicPrivacyController;
         mBypassHeadsUpNotifier = bypassHeadsUpNotifier;
+        mFalsingCollector = falsingCollector;
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
         mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
@@ -1389,7 +1393,7 @@
             where.getLocationInWindow(mTmpInt2);
             mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
                     mTmpInt2[1] + where.getHeight() / 2);
-            mFalsingManager.onScreenOnFromTouch();
+            mFalsingCollector.onScreenOnFromTouch();
         }
     }
 
@@ -1648,7 +1652,7 @@
             return;
         }
         mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD && !mDozing
-                && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
+                && mFalsingCollector.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
     }
 
     /**
@@ -3685,7 +3689,7 @@
     }
 
     public void onUnlockHintStarted() {
-        mFalsingManager.onUnlockHintStarted();
+        mFalsingCollector.onUnlockHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
     }
 
@@ -3695,17 +3699,17 @@
     }
 
     public void onCameraHintStarted() {
-        mFalsingManager.onCameraHintStarted();
+        mFalsingCollector.onCameraHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
     }
 
     public void onVoiceAssistHintStarted() {
-        mFalsingManager.onLeftAffordanceHintStarted();
+        mFalsingCollector.onLeftAffordanceHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
     }
 
     public void onPhoneHintStarted() {
-        mFalsingManager.onLeftAffordanceHintStarted();
+        mFalsingCollector.onLeftAffordanceHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
     }
 
@@ -3756,7 +3760,7 @@
         boolean fullShadeNeedsBouncer = !mLockscreenUserManager.
                 userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
                 || !mLockscreenUserManager.shouldShowLockscreenNotifications()
-                || mFalsingManager.shouldEnforceBouncer();
+                || mFalsingCollector.shouldEnforceBouncer();
         if (mKeyguardBypassController.getBypassEnabled()) {
             fullShadeNeedsBouncer = false;
         }
@@ -3888,7 +3892,7 @@
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
         @Override
         public void onScreenTurningOn() {
-            mFalsingManager.onScreenTurningOn();
+            mFalsingCollector.onScreenTurningOn();
             mNotificationPanelViewController.onScreenTurningOn();
         }
 
@@ -3899,7 +3903,7 @@
 
         @Override
         public void onScreenTurnedOff() {
-            mFalsingManager.onScreenOff();
+            mFalsingCollector.onScreenOff();
             mScrimController.onScreenTurnedOff();
             updateIsKeyguard();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index f6631ce..2aa3f37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -31,6 +31,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -136,6 +137,7 @@
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
             FalsingManager falsingManager,
+            FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
@@ -216,6 +218,7 @@
                 dynamicPrivacyController,
                 bypassHeadsUpNotifier,
                 falsingManager,
+                falsingCollector,
                 broadcastDispatcher,
                 remoteInputQuickSettingsDisabler,
                 notificationGutsManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 79f0915..adbc85b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -42,6 +42,7 @@
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.ContentInfo;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -590,12 +591,12 @@
                         new OnReceiveContentListener() {
                             @Override
                             @Nullable
-                            public Payload onReceiveContent(@NonNull View view,
-                                    @NonNull Payload payload) {
-                                Map<Boolean, Payload> split = payload.partition(
+                            public ContentInfo onReceiveContent(@NonNull View view,
+                                    @NonNull ContentInfo payload) {
+                                Map<Boolean, ContentInfo> split = payload.partition(
                                         item -> item.getUri() != null);
-                                Payload uriItems = split.get(true);
-                                Payload remainingItems = split.get(false);
+                                ContentInfo uriItems = split.get(true);
+                                ContentInfo remainingItems = split.get(false);
                                 if (uriItems != null) {
                                     ClipData clip = uriItems.getClip();
                                     ClipDescription description = clip.getDescription();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 2795857..bdf2b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -71,7 +71,6 @@
             // Creating AudioRecordingDisclosureBar and just letting it run
             new AudioRecordingDisclosureBar(mContext);
         }
-
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
new file mode 100644
index 0000000..3b1a4db
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tv.notifications;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.systemui.R;
+
+/**
+ * Adapter for the VerticalGridView of the TvNotificationsPanelView.
+ */
+public class TvNotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+    private static final String TAG = "TvNotificationAdapter";
+    private SparseArray<StatusBarNotification> mNotifications;
+
+    public TvNotificationAdapter() {
+        setHasStableIds(true);
+    }
+
+    @NonNull
+    @Override
+    public TvNotificationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.tv_notification_item,
+                parent, false);
+        return new TvNotificationViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+        if (mNotifications == null) {
+            Log.e(TAG, "Could not bind view holder because the notification is missing");
+            return;
+        }
+
+        TvNotificationViewHolder holder = (TvNotificationViewHolder) viewHolder;
+        Notification notification = mNotifications.valueAt(position).getNotification();
+        holder.mTitle.setText(notification.extras.getString(Notification.EXTRA_TITLE));
+        holder.mDetails.setText(notification.extras.getString(Notification.EXTRA_TEXT));
+        holder.mPendingIntent = notification.contentIntent;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mNotifications == null ? 0 : mNotifications.size();
+    }
+
+    @Override
+    public long getItemId(int position) {
+        // the item id is the notification id
+        return mNotifications.keyAt(position);
+    }
+
+    /**
+     * Updates the notifications and calls notifyDataSetChanged().
+     */
+    public void setNotifications(SparseArray<StatusBarNotification> notifications) {
+        this.mNotifications = notifications;
+        notifyDataSetChanged();
+    }
+
+    private static class TvNotificationViewHolder extends RecyclerView.ViewHolder implements
+            View.OnClickListener {
+        final TextView mTitle;
+        final TextView mDetails;
+        PendingIntent mPendingIntent;
+
+        protected TvNotificationViewHolder(View itemView) {
+            super(itemView);
+            mTitle = itemView.findViewById(R.id.tv_notification_title);
+            mDetails = itemView.findViewById(R.id.tv_notification_details);
+            itemView.setOnClickListener(this);
+        }
+
+        @Override
+        public void onClick(View v) {
+            try {
+                if (mPendingIntent != null) {
+                    mPendingIntent.send();
+                }
+            } catch (PendingIntent.CanceledException e) {
+                Log.d(TAG, "Pending intent canceled for : " + mPendingIntent);
+            }
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationHandler.java
new file mode 100644
index 0000000..d985803
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationHandler.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tv.notifications;
+
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.content.Context;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.NotificationListener;
+
+import javax.inject.Inject;
+
+/**
+ * Keeps track of the notifications on TV.
+ */
+public class TvNotificationHandler extends SystemUI implements
+        NotificationListener.NotificationHandler {
+    private static final String TAG = "TvNotificationHandler";
+    private final NotificationListener mNotificationListener;
+    private final SparseArray<StatusBarNotification> mNotifications = new SparseArray<>();
+    @Nullable
+    private Listener mUpdateListener;
+
+    @Inject
+    public TvNotificationHandler(Context context, NotificationListener notificationListener) {
+        super(context);
+        mNotificationListener = notificationListener;
+    }
+
+    public SparseArray<StatusBarNotification> getCurrentNotifications() {
+        return mNotifications;
+    }
+
+    public void setTvNotificationListener(Listener listener) {
+        mUpdateListener = listener;
+    }
+
+    @Override
+    public void start() {
+        mNotificationListener.addNotificationHandler(this);
+        mNotificationListener.registerAsSystemService();
+    }
+
+    @Override
+    public void onNotificationPosted(StatusBarNotification sbn,
+            NotificationListenerService.RankingMap rankingMap) {
+        if (!new Notification.TvExtender(sbn.getNotification()).isAvailableOnTv()) {
+            Log.v(TAG, "Notification not added because it isn't relevant for tv");
+            return;
+        }
+
+        mNotifications.put(sbn.getId(), sbn);
+        if (mUpdateListener != null) {
+            mUpdateListener.notificationsUpdated(mNotifications);
+        }
+        Log.d(TAG, "Notification added");
+    }
+
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn,
+            NotificationListenerService.RankingMap rankingMap) {
+
+        if (mNotifications.contains(sbn.getId())) {
+            mNotifications.remove(sbn.getId());
+            Log.d(TAG, "Notification removed");
+
+            if (mUpdateListener != null) {
+                mUpdateListener.notificationsUpdated(mNotifications);
+            }
+        }
+    }
+
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn,
+            NotificationListenerService.RankingMap rankingMap, int reason) {
+        onNotificationRemoved(sbn, rankingMap);
+    }
+
+    @Override
+    public void onNotificationRankingUpdate(NotificationListenerService.RankingMap rankingMap) {
+        // noop
+    }
+
+    @Override
+    public void onNotificationsInitialized() {
+        // noop
+    }
+
+    /**
+     * Get notified when the notifications are updated.
+     */
+    interface Listener {
+        void notificationsUpdated(SparseArray<StatusBarNotification> sbns);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
index 0bd3624..477424c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.tv;
+package com.android.systemui.statusbar.tv.notifications;
 
 import android.Manifest;
 import android.app.NotificationManager;
@@ -59,9 +59,8 @@
             startNotificationHandlerActivity(
                     new Intent(NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL));
         } else {
-            Log.w(TAG,
-                    "Not toggling notification panel: config_notificationHandlerPackage is "
-                            + "empty");
+            openInternalNotificationPanel(
+                    NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL);
         }
     }
 
@@ -71,9 +70,8 @@
             startNotificationHandlerActivity(
                     new Intent(NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL));
         } else {
-            Log.w(TAG,
-                    "Not expanding notification panel: config_notificationHandlerPackage is "
-                            + "empty");
+            openInternalNotificationPanel(
+                    NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL);
         }
     }
 
@@ -86,11 +84,17 @@
             closeNotificationIntent.setPackage(mNotificationHandlerPackage);
             mContext.sendBroadcastAsUser(closeNotificationIntent, UserHandle.CURRENT);
         } else {
-            Log.w(TAG,
-                    "Not closing notification panel: config_notificationHandlerPackage is empty");
+            openInternalNotificationPanel(
+                    NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL);
         }
     }
 
+    private void openInternalNotificationPanel(String action) {
+        Intent intent = new Intent(mContext, TvNotificationPanelActivity.class);
+        intent.setAction(action);
+        mContext.startActivityAsUser(intent, UserHandle.SYSTEM);
+    }
+
     /**
      * Starts the activity intent if all of the following are true
      * <ul>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java
new file mode 100644
index 0000000..30f401b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tv.notifications;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
+import android.util.SparseArray;
+import android.view.View;
+
+import androidx.leanback.widget.VerticalGridView;
+
+import com.android.systemui.R;
+
+import javax.inject.Inject;
+
+/**
+ * This Activity shows a notification panel for tv. It is used if no other app (e.g. a launcher) can
+ * be found to show the notifications.
+ */
+public class TvNotificationPanelActivity extends Activity implements
+        TvNotificationHandler.Listener {
+    private final TvNotificationHandler mTvNotificationHandler;
+    private TvNotificationAdapter mTvNotificationAdapter;
+    private VerticalGridView mNotificationListView;
+    private View mNotificationPlaceholder;
+    private boolean mPanelAlreadyOpen = false;
+
+    @Inject
+    public TvNotificationPanelActivity(TvNotificationHandler tvNotificationHandler) {
+        super();
+        mTvNotificationHandler = tvNotificationHandler;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (maybeClosePanel(getIntent())) {
+            return;
+        }
+        mPanelAlreadyOpen = true;
+
+        setContentView(R.layout.tv_notification_panel);
+
+        mNotificationPlaceholder = findViewById(R.id.no_tv_notifications);
+        mTvNotificationAdapter = new TvNotificationAdapter();
+
+        mNotificationListView = findViewById(R.id.notifications_list);
+        mNotificationListView.setAdapter(mTvNotificationAdapter);
+        mNotificationListView.setColumnWidth(R.dimen.tv_notification_panel_width);
+
+        mTvNotificationHandler.setTvNotificationListener(this);
+        notificationsUpdated(mTvNotificationHandler.getCurrentNotifications());
+    }
+
+    @Override
+    public void notificationsUpdated(@NonNull SparseArray<StatusBarNotification> notificationList) {
+        mTvNotificationAdapter.setNotifications(notificationList);
+
+        boolean noNotifications = notificationList.size() == 0;
+        mNotificationListView.setVisibility(noNotifications ? View.GONE : View.VISIBLE);
+        mNotificationPlaceholder.setVisibility(noNotifications ? View.VISIBLE : View.GONE);
+    }
+
+    @Override
+    public void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        maybeClosePanel(intent);
+    }
+
+    /**
+     * Handles intents from onCreate and onNewIntent.
+     *
+     * @return true if the panel is being closed, false if it is being opened
+     */
+    private boolean maybeClosePanel(Intent intent) {
+        if (NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL.equals(intent.getAction())
+                || (mPanelAlreadyOpen
+                && NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL.equals(
+                intent.getAction()))) {
+            finish();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mTvNotificationHandler.setTvNotificationListener(null);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index 2c3ea4f..353333f 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -16,14 +16,22 @@
 
 package com.android.systemui.tv;
 
+import com.android.systemui.SystemUI;
 import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.wmshell.TvPipModule;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler;
 
 import dagger.Binds;
 import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
 
 @Module
 interface TvSystemUIBinder {
     @Binds
     GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent);
+
+    @Binds
+    @IntoMap
+    @ClassKey(TvNotificationHandler.class)
+    SystemUI bindTvNotificationHandler(TvNotificationHandler systemui);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 8ffc7cf..56a4c203 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -43,6 +43,7 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsImplementation;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -62,6 +63,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler;
 
 import javax.inject.Named;
 
@@ -164,4 +166,11 @@
 
     @Binds
     abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost);
+
+    @Provides
+    @SysUISingleton
+    static TvNotificationHandler provideTvNotificationHandler(Context context,
+            NotificationListener notificationListener) {
+        return new TvNotificationHandler(context, notificationListener);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 411fbc3..a879a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -53,7 +53,6 @@
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.systemui.tracing.nano.SystemUiTraceProto;
 import com.android.wm.shell.ShellCommandHandler;
-import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.nano.WmShellTraceProto;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -99,13 +98,11 @@
     private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
     private final ProtoTracer mProtoTracer;
     private final Optional<ShellCommandHandler> mShellCommandHandler;
-    private final Optional<AppPairs> mAppPairsOptional;
 
     private boolean mIsSysUiStateValid;
     private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
     private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
     private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
-    private KeyguardUpdateMonitorCallback mAppPairsKeyguardCallback;
 
     @Inject
     public WMShell(Context context, CommandQueue commandQueue,
@@ -119,8 +116,7 @@
             Optional<OneHanded> oneHandedOptional,
             Optional<HideDisplayCutout> hideDisplayCutoutOptional,
             ProtoTracer protoTracer,
-            Optional<ShellCommandHandler> shellCommandHandler,
-            Optional<AppPairs> appPairsOptional) {
+            Optional<ShellCommandHandler> shellCommandHandler) {
         super(context);
         mCommandQueue = commandQueue;
         mConfigurationController = configurationController;
@@ -135,7 +131,6 @@
         mProtoTracer = protoTracer;
         mProtoTracer.add(this);
         mShellCommandHandler = shellCommandHandler;
-        mAppPairsOptional = appPairsOptional;
     }
 
     @Override
@@ -145,7 +140,6 @@
         mSplitScreenOptional.ifPresent(this::initSplitScreen);
         mOneHandedOptional.ifPresent(this::initOneHanded);
         mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
-        mAppPairsOptional.ifPresent(this::initAppPairs);
     }
 
     @VisibleForTesting
@@ -294,16 +288,6 @@
         });
     }
 
-    void initAppPairs(AppPairs appPairs) {
-        mAppPairsKeyguardCallback = new KeyguardUpdateMonitorCallback() {
-            @Override
-            public void onKeyguardVisibilityChanged(boolean showing) {
-                appPairs.onKeyguardVisibilityChanged(showing);
-            }
-        };
-        mKeyguardUpdateMonitor.registerCallback(mAppPairsKeyguardCallback);
-    }
-
     @Override
     public void writeToProto(SystemUiTraceProto proto) {
         if (proto.wmShell == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 4505b2a..7a1c058 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -84,10 +84,8 @@
     @WMSingleton
     @Provides
     static AppPairs provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
-            SyncTransactionQueue syncQueue, DisplayController displayController,
-            TaskStackListenerImpl taskStackListener) {
-        return new AppPairsController(shellTaskOrganizer, syncQueue, displayController,
-                taskStackListener);
+            SyncTransactionQueue syncQueue, DisplayController displayController) {
+        return new AppPairsController(shellTaskOrganizer, syncQueue, displayController);
     }
 
     @WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
index 2e8eb00..53d84db 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
@@ -17,7 +17,6 @@
 package com.android.keyguard
 
 import android.animation.ValueAnimator
-import android.graphics.Paint
 import android.testing.AndroidTestingRunner
 import android.text.Layout
 import android.text.StaticLayout
@@ -53,7 +52,7 @@
         val layout = makeLayout("Hello, World", PAINT[0])
         val valueAnimator = mock(ValueAnimator::class.java)
         val textInterpolator = mock(TextInterpolator::class.java)
-        val paint = arrayListOf(mock(Paint::class.java))
+        val paint = arrayListOf(mock(TextPaint::class.java))
         `when`(textInterpolator.targetPaint).thenReturn(paint)
 
         val textAnimator = TextAnimator(layout, {}).apply {
@@ -85,7 +84,7 @@
         val layout = makeLayout("Hello, World", PAINT[0])
         val valueAnimator = mock(ValueAnimator::class.java)
         val textInterpolator = mock(TextInterpolator::class.java)
-        val paint = arrayListOf(mock(Paint::class.java))
+        val paint = arrayListOf(mock(TextPaint::class.java))
         `when`(textInterpolator.targetPaint).thenReturn(paint)
 
         val textAnimator = TextAnimator(layout, {}).apply {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
index 002ba36..1206dab 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
@@ -18,11 +18,12 @@
 
 import android.graphics.Bitmap
 import android.graphics.Canvas
-import android.graphics.Paint
 import android.testing.AndroidTestingRunner
 import android.text.Layout
 import android.text.StaticLayout
 import android.text.TextPaint
+import android.text.TextDirectionHeuristic
+import android.text.TextDirectionHeuristics
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
@@ -31,6 +32,7 @@
 import kotlin.math.ceil
 
 private const val TEXT = "Hello, World."
+private const val BIDI_TEXT = "abc\u05D0\u05D1\u05D2"
 private const val BMP_WIDTH = 400
 private const val BMP_HEIGHT = 300
 
@@ -38,11 +40,11 @@
     textSize = 32f
 }
 
-private val START_PAINT = arrayListOf<Paint>(TextPaint(PAINT).apply {
+private val START_PAINT = arrayListOf(TextPaint(PAINT).apply {
     fontVariationSettings = "'wght' 400"
 })
 
-private val END_PAINT = arrayListOf<Paint>(TextPaint(PAINT).apply {
+private val END_PAINT = arrayListOf(TextPaint(PAINT).apply {
     fontVariationSettings = "'wght' 700"
 })
 
@@ -50,9 +52,14 @@
 @SmallTest
 class TextInterpolatorTest : SysuiTestCase() {
 
-    private fun makeLayout(text: String, paint: TextPaint): Layout {
+    private fun makeLayout(
+        text: String,
+        paint: TextPaint,
+        dir: TextDirectionHeuristic = TextDirectionHeuristics.LTR
+    ): Layout {
         val width = ceil(Layout.getDesiredWidth(text, 0, text.length, paint)).toInt()
-        return StaticLayout.Builder.obtain(text, 0, text.length, paint, width).build()
+        return StaticLayout.Builder.obtain(text, 0, text.length, paint, width)
+                .setTextDirection(dir).build()
     }
 
     @Test
@@ -69,7 +76,7 @@
         // Just after created TextInterpolator, it should have 0 progress.
         assertThat(interp.progress).isEqualTo(0f)
         val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
-        val expected = makeLayout(TEXT, START_PAINT[0] as TextPaint).toBitmap(BMP_WIDTH, BMP_HEIGHT)
+        val expected = makeLayout(TEXT, START_PAINT[0]).toBitmap(BMP_WIDTH, BMP_HEIGHT)
 
         assertThat(expected.sameAs(actual)).isTrue()
     }
@@ -87,7 +94,7 @@
 
         interp.progress = 1f
         val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
-        val expected = makeLayout(TEXT, END_PAINT[0] as TextPaint).toBitmap(BMP_WIDTH, BMP_HEIGHT)
+        val expected = makeLayout(TEXT, END_PAINT[0]).toBitmap(BMP_WIDTH, BMP_HEIGHT)
 
         assertThat(expected.sameAs(actual)).isTrue()
     }
@@ -108,9 +115,9 @@
         // end state.
         interp.progress = 0.5f
         val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
-        assertThat(actual.sameAs(makeLayout(TEXT, START_PAINT[0] as TextPaint)
+        assertThat(actual.sameAs(makeLayout(TEXT, START_PAINT[0])
             .toBitmap(BMP_WIDTH, BMP_HEIGHT))).isFalse()
-        assertThat(actual.sameAs(makeLayout(TEXT, END_PAINT[0] as TextPaint)
+        assertThat(actual.sameAs(makeLayout(TEXT, END_PAINT[0])
             .toBitmap(BMP_WIDTH, BMP_HEIGHT))).isFalse()
     }
 
@@ -135,10 +142,50 @@
 
         assertThat(expected.sameAs(actual)).isTrue()
     }
+
+    @Test
+    fun testBidi_LTR() {
+        val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.LTR)
+
+        val interp = TextInterpolator(layout)
+        TextInterpolator.updatePaint(interp.basePaint, START_PAINT)
+        interp.onBasePaintModified()
+
+        TextInterpolator.updatePaint(interp.targetPaint, END_PAINT)
+        interp.onTargetPaintModified()
+
+        // Just after created TextInterpolator, it should have 0 progress.
+        assertThat(interp.progress).isEqualTo(0f)
+        val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+        val expected = makeLayout(BIDI_TEXT, START_PAINT[0], TextDirectionHeuristics.LTR)
+                .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+        assertThat(expected.sameAs(actual)).isTrue()
+    }
+
+    @Test
+    fun testBidi_RTL() {
+        val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
+
+        val interp = TextInterpolator(layout)
+        TextInterpolator.updatePaint(interp.basePaint, START_PAINT)
+        interp.onBasePaintModified()
+
+        TextInterpolator.updatePaint(interp.targetPaint, END_PAINT)
+        interp.onTargetPaintModified()
+
+        // Just after created TextInterpolator, it should have 0 progress.
+        assertThat(interp.progress).isEqualTo(0f)
+        val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+        val expected = makeLayout(BIDI_TEXT, START_PAINT[0], TextDirectionHeuristics.RTL)
+                .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+        assertThat(expected.sameAs(actual)).isTrue()
+    }
 }
 
 private fun Layout.toBitmap(width: Int, height: Int) =
-        Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8).also { draw(Canvas(it)) }!!
+        Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }!!
 
 private fun TextInterpolator.toBitmap(width: Int, height: Int) =
-        Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8).also { draw(Canvas(it)) }
\ No newline at end of file
+        Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index ec0aa4c..30c4cf6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -33,6 +33,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -92,7 +93,7 @@
     @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
-    private IActivityTaskManager mActivityTaskManager;
+    private ActivityTaskManager mActivityTaskManager;
     @Mock
     private FingerprintManager mFingerprintManager;
     @Mock
@@ -553,7 +554,7 @@
 
         TestableAuthController(Context context, CommandQueue commandQueue,
                 StatusBarStateController statusBarStateController,
-                IActivityTaskManager activityTaskManager,
+                ActivityTaskManager activityTaskManager,
                 FingerprintManager fingerprintManager,
                 FaceManager faceManager,
                 Provider<UdfpsController> udfpsControllerFactory) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
similarity index 82%
rename from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
index 69d39fa..472ed7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
 
 import static com.android.systemui.classifier.Classifier.UNLOCK;
 
@@ -55,7 +55,7 @@
         resetDataProvider();
     }
 
-    FalsingDataProvider getDataProvider() {
+    protected FalsingDataProvider getDataProvider() {
         return mDataProvider;
     }
 
@@ -63,15 +63,15 @@
         return mFakeBatteryController;
     }
 
-    void setOffsetX(float offsetX) {
+    protected void setOffsetX(float offsetX) {
         mOffsetX = offsetX;
     }
 
-    void setOffsetY(float offsetY) {
+    protected void setOffsetY(float offsetY) {
         mOffsetY = offsetY;
     }
 
-    void resetDataProvider() {
+    protected void resetDataProvider() {
         for (MotionEvent motionEvent : mMotionEvents) {
             motionEvent.recycle();
         }
@@ -81,28 +81,28 @@
         mDataProvider.onSessionEnd();
     }
 
-    MotionEvent appendDownEvent(float x, float y) {
+    protected MotionEvent appendDownEvent(float x, float y) {
         return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y);
     }
 
-    MotionEvent appendDownEvent(float x, float y, long eventTime) {
+    protected MotionEvent appendDownEvent(float x, float y, long eventTime) {
         return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y, eventTime);
     }
 
-    MotionEvent appendMoveEvent(float x, float y) {
+    protected MotionEvent appendMoveEvent(float x, float y) {
         return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y);
     }
 
-    MotionEvent appendMoveEvent(float x, float y, long eventTime) {
+    protected MotionEvent appendMoveEvent(float x, float y, long eventTime) {
         return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y, eventTime);
     }
 
 
-    MotionEvent appendUpEvent(float x, float y) {
+    protected MotionEvent appendUpEvent(float x, float y) {
         return appendMotionEvent(MotionEvent.ACTION_UP, x, y);
     }
 
-    MotionEvent appendUpEvent(float x, float y, long eventTime) {
+    protected MotionEvent appendUpEvent(float x, float y, long eventTime) {
         return appendMotionEvent(MotionEvent.ACTION_UP, x, y, eventTime);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
new file mode 100644
index 0000000..af5e789
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.util.sensors.ProximitySensor;
+import com.android.systemui.util.sensors.ThresholdSensor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class FalsingCollectorImplTest extends SysuiTestCase {
+
+    private FalsingCollectorImpl mFalsingCollector;
+    @Mock
+    private FalsingDataProvider mFalsingDataProvider;
+    private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
+    @Mock
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock
+    private ProximitySensor mProximitySensor;
+    @Mock
+    private SysuiStatusBarStateController mStatusBarStateController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+
+        mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager,
+                mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController);
+    }
+
+
+    @Test
+    public void testRegisterSensor() {
+        mFalsingCollector.onScreenTurningOn();
+        verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
+    }
+
+    @Test
+    public void testNoProximityWhenWirelessCharging() {
+        when(mFalsingDataProvider.isWirelessCharging()).thenReturn(true);
+        mFalsingCollector.onScreenTurningOn();
+        verify(mProximitySensor, never()).register(any(ThresholdSensor.Listener.class));
+    }
+
+    @Test
+    public void testUnregisterSensor() {
+        mFalsingCollector.onScreenTurningOn();
+        reset(mProximitySensor);
+        mFalsingCollector.onScreenOff();
+        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
+    }
+
+    @Test
+    public void testUnregisterSensor_QS() {
+        mFalsingCollector.onScreenTurningOn();
+        reset(mProximitySensor);
+        mFalsingCollector.setQsExpanded(true);
+        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
+        mFalsingCollector.setQsExpanded(false);
+        verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
+    }
+
+    @Test
+    public void testUnregisterSensor_Bouncer() {
+        mFalsingCollector.onScreenTurningOn();
+        reset(mProximitySensor);
+        mFalsingCollector.onBouncerShown();
+        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
+        mFalsingCollector.onBouncerHidden();
+        verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
+    }
+
+    @Test
+    public void testUnregisterSensor_StateTransition() {
+
+        ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor =
+                ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+        verify(mStatusBarStateController).addCallback(stateListenerArgumentCaptor.capture());
+
+        mFalsingCollector.onScreenTurningOn();
+        reset(mProximitySensor);
+        stateListenerArgumentCaptor.getValue().onStateChanged(StatusBarState.SHADE);
+        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index be38f4419..be0cc97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.Matchers.closeTo;
@@ -112,13 +112,6 @@
         assertThat(motionEventList.get(1).getX(), is(6f));
         assertThat(motionEventList.get(0).getY(), is(7f));
         assertThat(motionEventList.get(1).getY(), is(5f));
-
-        // The first, real event should still be a, however.
-        MotionEvent firstRealMotionEvent = mDataProvider.getFirstActualMotionEvent();
-        assertThat(firstRealMotionEvent.getActionMasked(), is(MotionEvent.ACTION_DOWN));
-        assertThat(firstRealMotionEvent.getEventTime(), is(1L));
-        assertThat(firstRealMotionEvent.getX(), is(2f));
-        assertThat(firstRealMotionEvent.getY(), is(9f));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
deleted file mode 100644
index 30dddc0..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.classifier.brightline;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.res.Resources;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.util.DisplayMetrics;
-import android.view.ViewConfiguration;
-
-import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.R;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dock.DockManagerFake;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.DeviceConfigProxyFake;
-import com.android.systemui.util.sensors.ProximitySensor;
-import com.android.systemui.util.sensors.ThresholdSensor;
-import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.utils.leaks.FakeBatteryController;
-import com.android.systemui.utils.leaks.LeakCheckedTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class BrightLineFalsingManagerTest extends LeakCheckedTest {
-
-
-    @Mock
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock
-    private ProximitySensor mProximitySensor;
-    @Mock
-    private Resources mResources;
-    @Mock
-    private ViewConfiguration mViewConfiguration;
-    private SysuiStatusBarStateController mStatusBarStateController;
-    private FalsingDataProvider mFalsingDataProvider;
-    private FakeBatteryController mFakeBatteryController;
-
-    private BrightLineFalsingManager mFalsingManager;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mFakeBatteryController = new FakeBatteryController(getLeakCheck());
-        DisplayMetrics dm = new DisplayMetrics();
-        dm.xdpi = 100;
-        dm.ydpi = 100;
-        dm.widthPixels = 100;
-        dm.heightPixels = 100;
-        mFalsingDataProvider = new FalsingDataProvider(dm, mFakeBatteryController,
-                new FakeSystemClock());
-        DeviceConfigProxy deviceConfigProxy = new DeviceConfigProxyFake();
-        DockManager dockManager = new DockManagerFake();
-        mStatusBarStateController = new StatusBarStateControllerImpl(new UiEventLoggerFake());
-        mStatusBarStateController.setState(StatusBarState.KEYGUARD);
-        when(mResources.getDimension(R.dimen.double_tap_slop)).thenReturn(1f);
-        when(mViewConfiguration.getScaledTouchSlop()).thenReturn(1);
-        mFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
-                mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, mResources,
-                mViewConfiguration, dockManager, mStatusBarStateController);
-    }
-
-    @Test
-    public void testRegisterSensor() {
-        mFalsingManager.onScreenTurningOn();
-        verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
-    }
-
-    @Test
-    public void testNoProximityWhenWirelessCharging() {
-        mFakeBatteryController.setWirelessCharging(true);
-        mFalsingManager.onScreenTurningOn();
-        verify(mProximitySensor, never()).register(any(ThresholdSensor.Listener.class));
-    }
-
-    @Test
-    public void testUnregisterSensor() {
-        mFalsingManager.onScreenTurningOn();
-        reset(mProximitySensor);
-        mFalsingManager.onScreenOff();
-        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
-    }
-
-    @Test
-    public void testUnregisterSensor_QS() {
-        mFalsingManager.onScreenTurningOn();
-        reset(mProximitySensor);
-        mFalsingManager.setQsExpanded(true);
-        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
-        mFalsingManager.setQsExpanded(false);
-        verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
-    }
-
-    @Test
-    public void testUnregisterSensor_Bouncer() {
-        mFalsingManager.onScreenTurningOn();
-        reset(mProximitySensor);
-        mFalsingManager.onBouncerShown();
-        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
-        mFalsingManager.onBouncerHidden();
-        verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
-    }
-
-    @Test
-    public void testUnregisterSensor_StateTransition() {
-        mFalsingManager.onScreenTurningOn();
-        reset(mProximitySensor);
-        mStatusBarStateController.setState(StatusBarState.SHADE);
-        verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
index e88ff2d..714d658 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
@@ -27,6 +27,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.DeviceConfigProxyFake;
 
 import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
index e5ab9be..d66c7a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
@@ -23,6 +23,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.DeviceConfigProxyFake;
 
 import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
index 9f3a1e4..288ab0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
@@ -27,6 +27,9 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
index 4f8e7c8..b512f0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
@@ -26,6 +26,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
index 3cebf0d..c2e290f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
@@ -28,6 +28,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
 import com.android.systemui.util.DeviceConfigProxyFake;
 import com.android.systemui.util.sensors.ProximitySensor;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
index 642b077..d67f2b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
@@ -25,6 +25,9 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
index 4346e7d..5f3b84c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
@@ -33,6 +33,9 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
+import com.android.systemui.classifier.FalsingDataProvider;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
index a8cce00..e49262f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
@@ -23,6 +23,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.classifier.ClassifierTest;
 import com.android.systemui.util.DeviceConfigProxyFake;
 
 import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index f6d6f56..67d0295 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -41,7 +41,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -76,18 +76,18 @@
     private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
-    private FalsingManagerFake mFalsingManager;
+    private FalsingCollectorFake mFalsingCollector;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mFalsingManager = new FalsingManagerFake();
+        mFalsingCollector = new FalsingCollectorFake();
 
         when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
         when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
 
         mViewMediator = new KeyguardViewMediator(
-                mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
+                mContext, mFalsingCollector, mLockPatternUtils, mBroadcastDispatcher,
                 () -> mStatusBarKeyguardViewManager,
                 mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
                 mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 3e44fa4..477fe63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.people.widget;
 
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -164,7 +165,7 @@
         when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
 
         NotificationChannel channel =
-                mNoMan.createNotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME);
+                new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
 
         mNoMan.issueChannelModification(TEST_PACKAGE_A,
                 UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
@@ -181,7 +182,7 @@
         when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
 
         NotificationChannel channel =
-                mNoMan.createNotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME);
+                new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
         channel.setConversationId(TEST_PARENT_CHANNEL_ID, TEST_CONVERSATION_ID);
 
         mNoMan.issueChannelModification(TEST_PACKAGE_A,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 6fa6f31..fd0715b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -15,6 +15,7 @@
 package com.android.systemui.qs;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
 
 import static org.junit.Assert.assertFalse;
 import static org.mockito.Matchers.any;
@@ -24,6 +25,8 @@
 import static org.mockito.Mockito.when;
 
 import android.content.pm.UserInfo;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
@@ -75,6 +78,7 @@
     private ViewGroup mRootView;
     private TextView mFooterText;
     private TestableImageView mFooterIcon;
+    private TestableImageView mPrimaryFooterIcon;
     private QSSecurityFooter mFooter;
     @Mock
     private SecurityController mSecurityController;
@@ -95,6 +99,7 @@
                 mActivityStarter, mSecurityController, looper);
         mFooterText = mRootView.findViewById(R.id.footer_text);
         mFooterIcon = mRootView.findViewById(R.id.footer_icon);
+        mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
         mFooter.setHostEnvironment(null);
     }
 
@@ -119,6 +124,7 @@
                      mFooterText.getText());
         assertEquals(View.VISIBLE, mRootView.getVisibility());
         assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+        assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
         // -1 == never set.
         assertEquals(-1, mFooterIcon.getLastImageResource());
     }
@@ -136,6 +142,7 @@
                 mFooterText.getText());
         assertEquals(View.VISIBLE, mRootView.getVisibility());
         assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+        assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
         // -1 == never set.
         assertEquals(-1, mFooterIcon.getLastImageResource());
     }
@@ -165,6 +172,7 @@
         assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
                 mFooterText.getText());
         assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+        assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
         // -1 == never set.
         assertEquals(-1, mFooterIcon.getLastImageResource());
 
@@ -203,6 +211,7 @@
                                         VPN_PACKAGE),
                      mFooterText.getText());
         assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+        assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
         assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
 
         // Same situation, but with organization name set
@@ -229,6 +238,7 @@
         assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_vpns),
                      mFooterText.getText());
         assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+        assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
         assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
 
         // Same situation, but with organization name set
@@ -252,6 +262,7 @@
 
         TestableLooper.get(this).processAllMessages();
         assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+        assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
         assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
         assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
                 mFooterText.getText());
@@ -534,12 +545,27 @@
     @Test
     public void testParentalControls() {
         when(mSecurityController.isParentalControlsEnabled()).thenReturn(true);
+
+        Drawable testDrawable = new VectorDrawable();
+        when(mSecurityController.getIcon(any())).thenReturn(testDrawable);
+        assertNotNull(mSecurityController.getIcon(null));
+
         mFooter.refreshState();
 
         TestableLooper.get(this).processAllMessages();
 
         assertEquals(mContext.getString(R.string.quick_settings_disclosure_parental_controls),
                 mFooterText.getText());
+        assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+
+        assertEquals(testDrawable, mPrimaryFooterIcon.getDrawable());
+
+        // Ensure the primary icon is set to gone when parental controls is disabled.
+        when(mSecurityController.isParentalControlsEnabled()).thenReturn(false);
+        mFooter.refreshState();
+        TestableLooper.get(this).processAllMessages();
+
+        assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index 11ef3e3..b7cc651 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -19,6 +19,8 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 
 import android.app.PendingIntent;
@@ -128,6 +130,35 @@
         verify(mCallback).onRecordingEnd();
     }
 
+    // Test that broadcast will update state
+    @Test
+    public void testUpdateStateBroadcast() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        // When a recording has started
+        PendingIntent startIntent = Mockito.mock(PendingIntent.class);
+        mController.startCountdown(0, 0, startIntent, null);
+        verify(mCallback).onCountdownEnd();
+
+        // then the receiver was registered
+        verify(mBroadcastDispatcher).registerReceiver(eq(mController.mStateChangeReceiver),
+                any(), any(), any());
+
+        // When the receiver gets an update
+        Intent intent = new Intent(RecordingController.INTENT_UPDATE_STATE);
+        intent.putExtra(RecordingController.EXTRA_STATE, false);
+        mController.mStateChangeReceiver.onReceive(mContext, intent);
+
+        // then the state is updated
+        assertFalse(mController.isRecording());
+        verify(mCallback).onRecordingEnd();
+
+        // and the receiver is unregistered
+        verify(mBroadcastDispatcher).unregisterReceiver(eq(mController.mStateChangeReceiver));
+    }
+
     // Test that switching users will stop an ongoing recording
     @Test
     public void testUserChange() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 3e37fde..91cafea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -17,15 +17,18 @@
 package com.android.systemui.screenrecord;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.Intent;
+import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
@@ -43,6 +46,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.io.IOException;
 import java.util.concurrent.Executor;
 
 @RunWith(AndroidTestingRunner.class)
@@ -88,6 +92,9 @@
         doNothing().when(mRecordingService).createRecordingNotification();
         doReturn(mNotification).when(mRecordingService).createProcessingNotification();
         doReturn(mNotification).when(mRecordingService).createSaveNotification(any());
+        doNothing().when(mRecordingService).createErrorNotification();
+        doNothing().when(mRecordingService).showErrorToast(anyInt());
+        doNothing().when(mRecordingService).stopForeground(anyBoolean());
 
         doNothing().when(mRecordingService).startForeground(anyInt(), any());
         doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
@@ -124,4 +131,16 @@
                 .log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
         verify(mUiEventLogger, times(0)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
     }
+
+    @Test
+    public void testErrorUpdatesState() throws IOException, RemoteException {
+        // When the screen recording does not start properly
+        doThrow(new RuntimeException("fail")).when(mScreenMediaRecorder).start();
+
+        Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false);
+        mRecordingService.onStartCommand(startIntent, 0, 0);
+
+        // Then the state is set to not recording
+        verify(mController).updateState(false);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
index 1bfe10c5..4507366 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-
 import static org.junit.Assert.assertNotNull;
 
 import android.app.NotificationChannel;
@@ -76,10 +74,6 @@
         }
     }
 
-    public NotificationChannel createNotificationChannel(String id, String name) {
-        return new NotificationChannel(id, name, IMPORTANCE_DEFAULT);
-    }
-
     public void issueChannelModification(
             String pkg, UserHandle user, NotificationChannel channel, int modificationType) {
         for (NotificationHandler listener : mListeners) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index dbaf5c4..ababebd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -44,9 +44,9 @@
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.media.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.FeatureFlags;
@@ -129,7 +129,6 @@
     @Mock(answer = Answers.RETURNS_SELF)
     private ExpandableNotificationRowComponent.Builder mExpandableNotificationRowComponentBuilder;
     @Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent;
-    @Mock private FalsingManager mFalsingManager;
     @Mock private KeyguardBypassController mKeyguardBypassController;
     @Mock private StatusBarStateController mStatusBarStateController;
 
@@ -244,7 +243,7 @@
                                 mGutsManager,
                                 true,
                                 null,
-                                mFalsingManager,
+                                new FalsingCollectorFake(),
                                 mPeopleNotificationIdentifier,
                                 Optional.of(mock(BubblesManager.class))
                         ));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
index 7f48cd1..edf2b4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
@@ -69,32 +69,4 @@
         assertEquals("Height matches new config", mResolver.mMaxImageHeight, 20);
         assertEquals("Width matches new config", mResolver.mMaxImageWidth, 15);
     }
-
-    @Test
-    public void resolveImage_sizeTooBig() throws IOException {
-        doReturn(mBitmapDrawable).when(mResolver).resolveImageInternal(mUri);
-        mResolver.mMaxImageHeight = 5;
-        mResolver.mMaxImageWidth = 5;
-
-        // original bitmap size is 10x10
-        BitmapDrawable resolved = (BitmapDrawable) mResolver.resolveImage(mUri);
-        Bitmap resolvedBitmap = resolved.getBitmap();
-        assertEquals("Bitmap width reduced", 5, resolvedBitmap.getWidth());
-        assertEquals("Bitmap height reduced", 5, resolvedBitmap.getHeight());
-        assertNotSame("Bitmap replaced", resolvedBitmap, mBitmap);
-    }
-
-    @Test
-    public void resolveImage_sizeOK() throws IOException {
-        doReturn(mBitmapDrawable).when(mResolver).resolveImageInternal(mUri);
-        mResolver.mMaxImageWidth = 15;
-        mResolver.mMaxImageHeight = 15;
-
-        // original bitmap size is 10x10
-        BitmapDrawable resolved = (BitmapDrawable) mResolver.resolveImage(mUri);
-        Bitmap resolvedBitmap = resolved.getBitmap();
-        assertEquals("Bitmap width unchanged", 10, resolvedBitmap.getWidth());
-        assertEquals("Bitmap height unchanged", 10, resolvedBitmap.getHeight());
-        assertSame("Bitmap not replaced", resolvedBitmap, mBitmap);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index baae8fd..7470a13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -45,9 +45,9 @@
 
 import com.android.systemui.R;
 import com.android.systemui.TestableDependency;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.media.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -428,7 +428,7 @@
                 mock(OnExpandClickListener.class),
                 mock(NotificationMediaManager.class),
                 mock(ExpandableNotificationRow.CoordinateOnClickListener.class),
-                mock(FalsingManager.class),
+                new FalsingCollectorFake(),
                 mStatusBarStateController,
                 mPeopleNotificationIdentifier,
                 mock(OnUserInteractionCallback.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index 01d49c2..3c4fde8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -42,9 +42,9 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.media.KeyguardMediaController;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -106,7 +106,6 @@
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     @Mock private MetricsLogger mMetricsLogger;
-    @Mock private FalsingManager mFalsingManager;
     @Mock private Resources mResources;
     @Mock(answer = Answers.RETURNS_SELF)
     private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
@@ -160,7 +159,7 @@
                 mColorExtractor,
                 mNotificationLockscreenUserManager,
                 mMetricsLogger,
-                mFalsingManager,
+                new FalsingCollectorFake(),
                 mResources,
                 mNotificationSwipeHelperBuilder,
                 mStatusBar,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 1b05ad7..bc014ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -50,9 +50,9 @@
 import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Assert;
@@ -72,7 +72,7 @@
 public class KeyguardBouncerTest extends SysuiTestCase {
 
     @Mock
-    private FalsingManager mFalsingManager;
+    private FalsingCollector mFalsingCollector;
     @Mock
     private ViewMediatorCallback mViewMediatorCallback;
     @Mock
@@ -128,7 +128,7 @@
 
         final ViewGroup container = new FrameLayout(getContext());
         mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
-                mDismissCallbackRegistry, mFalsingManager,
+                mDismissCallbackRegistry, mFalsingCollector,
                 mKeyguardStateController, mKeyguardUpdateMonitor,
                 mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
                 mKeyguardBouncerComponentFactory)
@@ -143,10 +143,10 @@
     @Test
     public void testShow_notifiesFalsingManager() {
         mBouncer.show(true);
-        verify(mFalsingManager).onBouncerShown();
+        verify(mFalsingCollector).onBouncerShown();
 
         mBouncer.show(true, false);
-        verifyNoMoreInteractions(mFalsingManager);
+        verifyNoMoreInteractions(mFalsingCollector);
     }
 
     /**
@@ -212,11 +212,11 @@
         mBouncer.setExpansion(0.5f);
 
         mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
-        verify(mFalsingManager).onBouncerHidden();
+        verify(mFalsingCollector).onBouncerHidden();
         verify(mExpansionCallback).onFullyHidden();
 
         mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
-        verify(mFalsingManager).onBouncerShown();
+        verify(mFalsingCollector).onBouncerShown();
         verify(mExpansionCallback).onFullyShown();
 
         verify(mExpansionCallback, never()).onStartingToHide();
@@ -239,7 +239,7 @@
     @Test
     public void testHide_notifiesFalsingManager() {
         mBouncer.hide(false);
-        verify(mFalsingManager).onBouncerHidden();
+        verify(mFalsingCollector).onBouncerHidden();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 4841b3b..3d582e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -60,10 +60,10 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.media.MediaHierarchyManager;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.qs.QSDetailDisplayer;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -132,8 +132,6 @@
     @Mock
     private KeyguardUpdateMonitor mUpdateMonitor;
     @Mock
-    private FalsingManager mFalsingManager;
-    @Mock
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private DozeParameters mDozeParameters;
@@ -252,7 +250,7 @@
                 mKeyguardBypassController, mHeadsUpManager,
                 mock(NotificationRoundnessManager.class),
                 mStatusBarStateController,
-                new FalsingManagerFake());
+                new FalsingManagerFake(), new FalsingCollectorFake());
         when(mKeyguardStatusViewComponentFactory.build(any()))
                 .thenReturn(mKeyguardStatusViewComponent);
         when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -263,7 +261,7 @@
                 mResources,
                 mInjectionInflationController,
                 coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
-                mFalsingManager, mShadeController,
+                new FalsingManagerFake(), new FalsingCollectorFake(), mShadeController,
                 mNotificationLockscreenUserManager, mNotificationEntryManager,
                 mKeyguardStateController, mStatusBarStateController, mDozeLog,
                 mDozeParameters, mCommandQueue, mVibratorHelper,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 25af584..e0fa9bab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -30,6 +30,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeLog;
@@ -111,6 +112,7 @@
                 mDynamicPrivacyController,
                 mBypassController,
                 new FalsingManagerFake(),
+                new FalsingCollectorFake(),
                 mPluginManager,
                 mTunerService,
                 mNotificationLockScreenUserManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 710122d..5416f75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -83,6 +83,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.demomode.DemoModeController;
@@ -356,6 +357,7 @@
                 mDynamicPrivacyController,
                 mBypassHeadsUpNotifier,
                 new FalsingManagerFake(),
+                new FalsingCollectorFake(),
                 mBroadcastDispatcher,
                 new RemoteInputQuickSettingsDisabler(
                         mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 822a6f2..ef25b73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -34,7 +34,6 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.wm.shell.ShellCommandHandler;
-import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.onehanded.OneHandedGestureHandler;
@@ -69,7 +68,6 @@
     @Mock HideDisplayCutout mHideDisplayCutout;
     @Mock ProtoTracer mProtoTracer;
     @Mock ShellCommandHandler mShellCommandHandler;
-    @Mock AppPairs mAppPairs;
 
     @Before
     public void setUp() {
@@ -79,7 +77,7 @@
                 mKeyguardUpdateMonitor, mNavigationModeController,
                 mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
                 Optional.of(mOneHanded), Optional.of(mHideDisplayCutout), mProtoTracer,
-                Optional.of(mShellCommandHandler), Optional.of(mAppPairs));
+                Optional.of(mShellCommandHandler));
 
         when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler);
     }
diff --git a/packages/services/PacProcessor/AndroidManifest.xml b/packages/services/PacProcessor/AndroidManifest.xml
index ad13261..533098c 100644
--- a/packages/services/PacProcessor/AndroidManifest.xml
+++ b/packages/services/PacProcessor/AndroidManifest.xml
@@ -3,6 +3,7 @@
     package="com.android.pacprocessor">
 
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 
     <application
         android:label="@string/app_name"
diff --git a/services/Android.bp b/services/Android.bp
index eb7b72e..1101e2a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -9,6 +9,7 @@
     name: "services-all-sources",
     srcs: [
         ":services.core-sources",
+        ":services.core-sources-am-wm",
         ":services.accessibility-sources",
         ":services.appprediction-sources",
         ":services.appwidget-sources",
diff --git a/services/autofill/java/com/android/server/autofill/TEST_MAPPING b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
new file mode 100644
index 0000000..cf058ad
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAutoFillServiceTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/services/companion/java/com/android/server/companion/OWNERS b/services/companion/java/com/android/server/companion/OWNERS
new file mode 100644
index 0000000..da723b3
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com
\ No newline at end of file
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 069a5ea..614863d 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -1,7 +1,20 @@
 filegroup {
+    name: "services.core-sources-am-wm",
+    srcs: [
+        "java/com/android/server/am/**/*.java",
+        "java/com/android/server/wm/**/*.java",
+    ],
+    path: "java",
+    visibility: ["//frameworks/base/services"],
+}
+
+filegroup {
     name: "services.core-sources",
     srcs: ["java/**/*.java"],
-    exclude_srcs: [":connectivity-service-srcs"],
+    exclude_srcs: [
+        ":connectivity-service-srcs",
+        ":services.core-sources-am-wm"
+    ],
     path: "java",
     visibility: [
         "//frameworks/base/services",
@@ -13,7 +26,7 @@
     name: "services.core.protologsrc",
     srcs: [
         ":protolog-groups",
-        ":services.core-sources",
+        ":services.core-sources-am-wm",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
@@ -23,7 +36,7 @@
       "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
       "--loggroups-jar $(location :protolog-groups) " +
       "--output-srcjar $(out) " +
-      "$(locations :services.core-sources)",
+      "$(locations :services.core-sources-am-wm)",
     out: ["services.core.protolog.srcjar"],
 }
 
@@ -31,7 +44,7 @@
     name: "generate-protolog.json",
     srcs: [
         ":protolog-groups",
-        ":services.core-sources",
+        ":services.core-sources-am-wm",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) generate-viewer-config " +
@@ -39,7 +52,7 @@
       "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
       "--loggroups-jar $(location :protolog-groups) " +
       "--viewer-conf $(out) " +
-      "$(locations :services.core-sources)",
+      "$(locations :services.core-sources-am-wm)",
     out: ["services.core.protolog.json"],
 }
 
@@ -63,6 +76,7 @@
     name: "services.core.unboosted",
     defaults: ["platform_service_defaults"],
     srcs: [
+        ":services.core-sources",
         ":services.core.protologsrc",
         ":dumpstate_aidl",
         ":framework_native_aidl",
@@ -174,6 +188,13 @@
     src: ":services.core.json.gz",
 }
 
+filegroup {
+    name: "services.core-sources-deviceconfig-interface",
+    srcs: [
+         "java/com/android/server/utils/DeviceConfigInterface.java"
+    ],
+}
+
 // TODO: Move connectivity service sources to independent directory.
 filegroup {
     name: "connectivity-service-srcs",
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index fa84427..b2226d1 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -326,4 +326,18 @@
      * @return {@code true} if the updating was successful, {@code false} otherwise
      */
     public abstract boolean updatePackageMappingsData();
+
+    /**
+     * Listener interface for usage events.
+     */
+    public interface UsageEventListener {
+        /** Callback to inform listeners of a new usage event. */
+        void onUsageEvent(@UserIdInt int userId, @NonNull UsageEvents.Event event);
+    }
+
+    /** Register a listener that will be notified of every new usage event. */
+    public abstract void registerListener(@NonNull UsageEventListener listener);
+
+    /** Unregister a listener from being notified of every new usage event. */
+    public abstract void unregisterListener(@NonNull UsageEventListener listener);
 }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index f205662..6989e32 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -77,6 +77,7 @@
             PACKAGE_WIFI,
             PACKAGE_COMPANION,
             PACKAGE_RETAIL_DEMO,
+            PACKAGE_RECENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface KnownPackage {}
@@ -97,9 +98,10 @@
     public static final int PACKAGE_WIFI = 13;
     public static final int PACKAGE_COMPANION = 14;
     public static final int PACKAGE_RETAIL_DEMO = 15;
+    public static final int PACKAGE_RECENTS = 16;
     // Integer value of the last known package ID. Increases as new ID is added to KnownPackage.
     // Please note the numbers should be continuous.
-    public static final int LAST_KNOWN_PACKAGE = PACKAGE_RETAIL_DEMO;
+    public static final int LAST_KNOWN_PACKAGE = PACKAGE_RECENTS;
 
     @IntDef(flag = true, prefix = "RESOLVE_", value = {
             RESOLVE_NON_BROWSER_ONLY,
@@ -1060,6 +1062,8 @@
                 return "Retail Demo";
             case PACKAGE_OVERLAY_CONFIG_SIGNATURE:
                 return "Overlay Config Signature";
+            case PACKAGE_RECENTS:
+                return "Recents";
         }
         return "Unknown";
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2fe37d4..e8ee18c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2771,6 +2771,7 @@
                         networkCapabilities = new NetworkCapabilities(networkCapabilities);
                         networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid);
                     }
+                    processCapabilitiesFromAgent(nai, networkCapabilities);
                     updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
                     break;
                 }
@@ -2809,6 +2810,31 @@
                     mKeepaliveTracker.handleEventSocketKeepalive(nai, msg);
                     break;
                 }
+                case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
+                    if (!nai.supportsUnderlyingNetworks()) {
+                        Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
+                        break;
+                    }
+                    final ArrayList<Network> underlying;
+                    try {
+                        underlying = ((Bundle) msg.obj).getParcelableArrayList(
+                                NetworkAgent.UNDERLYING_NETWORKS_KEY);
+                    } catch (NullPointerException | ClassCastException e) {
+                        break;
+                    }
+                    final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
+                    nai.declaredUnderlyingNetworks = (underlying != null)
+                            ? underlying.toArray(new Network[0]) : null;
+
+                    if (!Arrays.equals(oldUnderlying, nai.declaredUnderlyingNetworks)) {
+                        if (DBG) {
+                            log(nai.toShortString() + " changed underlying networks to "
+                                    + Arrays.toString(nai.declaredUnderlyingNetworks));
+                        }
+                        updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+                        notifyIfacesChangedForNetworkStats();
+                    }
+                }
             }
         }
 
@@ -3394,7 +3420,7 @@
         }
         mLegacyTypeTracker.remove(nai, wasDefault);
         if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
-            updateAllVpnsCapabilities();
+            propagateUnderlyingNetworkCapabilities();
         }
         rematchAllNetworksAndRequests();
         mLingerMonitor.noteDisconnect(nai);
@@ -4704,10 +4730,9 @@
             if (mLockdownEnabled) {
                 return new VpnInfo[0];
             }
-
             List<VpnInfo> infoList = new ArrayList<>();
-            for (int i = 0; i < mVpns.size(); i++) {
-                VpnInfo info = createVpnInfo(mVpns.valueAt(i));
+            for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+                VpnInfo info = createVpnInfo(nai);
                 if (info != null) {
                     infoList.add(info);
                 }
@@ -4720,13 +4745,10 @@
      * @return VPN information for accounting, or null if we can't retrieve all required
      *         information, e.g underlying ifaces.
      */
-    @Nullable
-    private VpnInfo createVpnInfo(Vpn vpn) {
-        VpnInfo info = vpn.getVpnInfo();
-        if (info == null) {
-            return null;
-        }
-        Network[] underlyingNetworks = vpn.getUnderlyingNetworks();
+    private VpnInfo createVpnInfo(NetworkAgentInfo nai) {
+        if (!nai.isVPN()) return null;
+
+        Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
         // see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
         // the underlyingNetworks list.
         if (underlyingNetworks == null) {
@@ -4735,23 +4757,33 @@
                 underlyingNetworks = new Network[] { defaultNai.network };
             }
         }
-        if (underlyingNetworks != null && underlyingNetworks.length > 0) {
-            List<String> interfaces = new ArrayList<>();
-            for (Network network : underlyingNetworks) {
-                LinkProperties lp = getLinkProperties(network);
-                if (lp != null) {
-                    for (String iface : lp.getAllInterfaceNames()) {
-                        if (!TextUtils.isEmpty(iface)) {
-                            interfaces.add(iface);
-                        }
-                    }
+
+        if (ArrayUtils.isEmpty(underlyingNetworks)) return null;
+
+        List<String> interfaces = new ArrayList<>();
+        for (Network network : underlyingNetworks) {
+            NetworkAgentInfo underlyingNai = getNetworkAgentInfoForNetwork(network);
+            if (underlyingNai == null) continue;
+            LinkProperties lp = underlyingNai.linkProperties;
+            for (String iface : lp.getAllInterfaceNames()) {
+                if (!TextUtils.isEmpty(iface)) {
+                    interfaces.add(iface);
                 }
             }
-            if (!interfaces.isEmpty()) {
-                info.underlyingIfaces = interfaces.toArray(new String[interfaces.size()]);
-            }
         }
-        return info.underlyingIfaces == null ? null : info;
+
+        if (interfaces.isEmpty()) return null;
+
+        VpnInfo info = new VpnInfo();
+        info.ownerUid = nai.networkCapabilities.getOwnerUid();
+        info.vpnIface = nai.linkProperties.getInterfaceName();
+        // Must be non-null or NetworkStatsService will crash.
+        // Cannot happen in production code because Vpn only registers the NetworkAgent after the
+        // tun or ipsec interface is created.
+        if (info.vpnIface == null) return null;
+        info.underlyingIfaces = interfaces.toArray(new String[0]);
+
+        return info;
     }
 
     /**
@@ -4774,35 +4806,21 @@
     }
 
     /**
-     * Ask all VPN objects to recompute and update their capabilities.
+     * Ask all networks with underlying networks to recompute and update their capabilities.
      *
-     * When underlying networks change, VPNs may have to update capabilities to reflect things
-     * like the metered bit, their transports, and so on. This asks the VPN objects to update
-     * their capabilities, and as this will cause them to send messages to the ConnectivityService
-     * handler thread through their agent, this is asynchronous. When the capabilities objects
-     * are computed they will be up-to-date as they are computed synchronously from here and
-     * this is running on the ConnectivityService thread.
+     * When underlying networks change, such networks may have to update capabilities to reflect
+     * things like the metered bit, their transports, and so on. The capabilities are calculated
+     * immediately. This method runs on the ConnectivityService thread.
      */
-    private void updateAllVpnsCapabilities() {
-        Network defaultNetwork = getNetwork(getDefaultNetwork());
-        synchronized (mVpns) {
-            for (int i = 0; i < mVpns.size(); i++) {
-                final Vpn vpn = mVpns.valueAt(i);
-                NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
-                updateVpnCapabilities(vpn, nc);
+    private void propagateUnderlyingNetworkCapabilities() {
+        ensureRunningOnConnectivityServiceThread();
+        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            if (nai.supportsUnderlyingNetworks()) {
+                updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
             }
         }
     }
 
-    private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) {
-        ensureRunningOnConnectivityServiceThread();
-        NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId());
-        if (vpnNai == null || nc == null) {
-            return;
-        }
-        updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc);
-    }
-
     @Override
     public boolean updateLockdownVpn() {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -5113,7 +5131,7 @@
         }
     }
 
-    private void onUserStart(int userId) {
+    private void onUserStarted(int userId) {
         synchronized (mVpns) {
             Vpn userVpn = mVpns.get(userId);
             if (userVpn != null) {
@@ -5128,7 +5146,7 @@
         }
     }
 
-    private void onUserStop(int userId) {
+    private void onUserStopped(int userId) {
         synchronized (mVpns) {
             Vpn userVpn = mVpns.get(userId);
             if (userVpn == null) {
@@ -5142,28 +5160,22 @@
 
     private void onUserAdded(int userId) {
         mPermissionMonitor.onUserAdded(userId);
-        Network defaultNetwork = getNetwork(getDefaultNetwork());
         synchronized (mVpns) {
             final int vpnsSize = mVpns.size();
             for (int i = 0; i < vpnsSize; i++) {
                 Vpn vpn = mVpns.valueAt(i);
                 vpn.onUserAdded(userId);
-                NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
-                updateVpnCapabilities(vpn, nc);
             }
         }
     }
 
     private void onUserRemoved(int userId) {
         mPermissionMonitor.onUserRemoved(userId);
-        Network defaultNetwork = getNetwork(getDefaultNetwork());
         synchronized (mVpns) {
             final int vpnsSize = mVpns.size();
             for (int i = 0; i < vpnsSize; i++) {
                 Vpn vpn = mVpns.valueAt(i);
                 vpn.onUserRemoved(userId);
-                NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
-                updateVpnCapabilities(vpn, nc);
             }
         }
     }
@@ -5245,9 +5257,9 @@
             if (userId == UserHandle.USER_NULL) return;
 
             if (Intent.ACTION_USER_STARTED.equals(action)) {
-                onUserStart(userId);
+                onUserStarted(userId);
             } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
-                onUserStop(userId);
+                onUserStopped(userId);
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 onUserAdded(userId);
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
@@ -5959,13 +5971,29 @@
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
         if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
             enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
+        } else {
+            enforceNetworkFactoryPermission();
+        }
+
+        final int uid = Binder.getCallingUid();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return registerNetworkAgentInternal(messenger, networkInfo, linkProperties,
+                    networkCapabilities, currentScore, networkAgentConfig, providerId, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private Network registerNetworkAgentInternal(Messenger messenger, NetworkInfo networkInfo,
+            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+            int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) {
+        if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
             // Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
             // the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
             // sees capabilities that may be malicious, which might prevent mistakes in the future.
             networkCapabilities = new NetworkCapabilities(networkCapabilities);
-            networkCapabilities.restrictCapabilitesForTestNetwork(Binder.getCallingUid());
-        } else {
-            enforceNetworkFactoryPermission();
+            networkCapabilities.restrictCapabilitesForTestNetwork(uid);
         }
 
         LinkProperties lp = new LinkProperties(linkProperties);
@@ -5976,9 +6004,10 @@
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
                 currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
-                this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid());
+                this, mNetd, mDnsResolver, mNMS, providerId, uid);
 
         // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
+        processCapabilitiesFromAgent(nai, nc);
         nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
         processLinkPropertiesFromAgent(nai, nai.linkProperties);
 
@@ -5986,13 +6015,8 @@
         final String name = TextUtils.isEmpty(extraInfo)
                 ? nai.networkCapabilities.getSsid() : extraInfo;
         if (DBG) log("registerNetworkAgent " + nai);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mDeps.getNetworkStack().makeNetworkMonitor(
-                    nai.network, name, new NetworkMonitorCallbacks(nai));
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mDeps.getNetworkStack().makeNetworkMonitor(
+                nai.network, name, new NetworkMonitorCallbacks(nai));
         // NetworkAgentInfo registration will finish when the NetworkMonitor is created.
         // If the network disconnects or sends any other event before that, messages are deferred by
         // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
@@ -6019,6 +6043,12 @@
         updateUids(nai, null, nai.networkCapabilities);
     }
 
+    /**
+     * Called when receiving LinkProperties directly from a NetworkAgent.
+     * Stores into |nai| any data coming from the agent that might also be written to the network's
+     * LinkProperties by ConnectivityService itself. This ensures that the data provided by the
+     * agent is not lost when updateLinkProperties is called.
+     */
     private void processLinkPropertiesFromAgent(NetworkAgentInfo nai, LinkProperties lp) {
         lp.ensureDirectlyConnectedRoutes();
         nai.clatd.setNat64PrefixFromRa(lp.getNat64Prefix());
@@ -6315,6 +6345,30 @@
     }
 
     /**
+     * Called when receiving NetworkCapabilities directly from a NetworkAgent.
+     * Stores into |nai| any data coming from the agent that might also be written to the network's
+     * NetworkCapabilities by ConnectivityService itself. This ensures that the data provided by the
+     * agent is not lost when updateCapabilities is called.
+     */
+    private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
+        nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
+    }
+
+    /** Propagates to |nc| the capabilities declared by the underlying networks of |nai|. */
+    private void mixInUnderlyingCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
+        Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
+        Network defaultNetwork = getNetwork(getDefaultNetwork());
+        if (underlyingNetworks == null && defaultNetwork != null) {
+            // null underlying networks means to track the default.
+            underlyingNetworks = new Network[] { defaultNetwork };
+        }
+
+        // TODO(b/124469351): Get capabilities directly from ConnectivityService instead.
+        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        Vpn.applyUnderlyingCapabilities(cm, underlyingNetworks, nc, nai.declaredMetered);
+    }
+
+    /**
      * Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
      * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
      * and foreground status).
@@ -6367,6 +6421,10 @@
             newNc.addCapability(NET_CAPABILITY_NOT_ROAMING);
         }
 
+        if (nai.supportsUnderlyingNetworks()) {
+            mixInUnderlyingCapabilities(nai, newNc);
+        }
+
         return newNc;
     }
 
@@ -6446,7 +6504,7 @@
         if (!newNc.hasTransport(TRANSPORT_VPN)) {
             // Tell VPNs about updated capabilities, since they may need to
             // bubble those changes through.
-            updateAllVpnsCapabilities();
+            propagateUnderlyingNetworkCapabilities();
         }
 
         if (!newNc.equalsTransportTypes(prevNc)) {
@@ -6766,7 +6824,7 @@
                 ? newNetwork.linkProperties.getTcpBufferSizes() : null);
         notifyIfacesChangedForNetworkStats();
         // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
-        updateAllVpnsCapabilities();
+        propagateUnderlyingNetworkCapabilities();
     }
 
     private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -7228,7 +7286,7 @@
                 // onCapabilitiesUpdated being sent in updateAllVpnCapabilities below as
                 // the VPN would switch from its default, blank capabilities to those
                 // that reflect the capabilities of its underlying networks.
-                updateAllVpnsCapabilities();
+                propagateUnderlyingNetworkCapabilities();
             }
             networkAgent.created = true;
         }
@@ -7270,8 +7328,8 @@
             // doing.
             updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
 
-            if (networkAgent.isVPN()) {
-                updateAllVpnsCapabilities();
+            if (networkAgent.supportsUnderlyingNetworks()) {
+                propagateUnderlyingNetworkCapabilities();
             }
 
             // Consider network even though it is not yet validated.
@@ -7528,13 +7586,6 @@
             throwIfLockdownEnabled();
             success = mVpns.get(user).setUnderlyingNetworks(networks);
         }
-        if (success) {
-            mHandler.post(() -> {
-                // Update VPN's capabilities based on updated underlying network set.
-                updateAllVpnsCapabilities();
-                notifyIfacesChangedForNetworkStats();
-            });
-        }
         return success;
     }
 
@@ -8210,13 +8261,12 @@
             return false;
         }
 
-        final Network[] underlyingNetworks;
-        synchronized (mVpns) {
-            final Vpn vpn = getVpnIfOwner(callbackUid);
-            underlyingNetworks = (vpn == null) ? null : vpn.getUnderlyingNetworks();
-        }
-        if (underlyingNetworks != null) {
-            if (Arrays.asList(underlyingNetworks).contains(nai.network)) return true;
+        for (NetworkAgentInfo virtual : mNetworkAgentInfos.values()) {
+            if (virtual.supportsUnderlyingNetworks()
+                    && virtual.networkCapabilities.getOwnerUid() == callbackUid
+                    && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
+                return true;
+            }
         }
 
         // Administrator UIDs also contains the Owner UID
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index e67b9d8..8706cdf 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -6,3 +6,6 @@
 
 # Zram writeback
 per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
+
+# Userspace reboot
+per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 735d248..9bf63cb 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -47,7 +47,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 
@@ -64,7 +63,6 @@
 import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -129,9 +127,17 @@
     @VisibleForTesting
     static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5;
     static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
+
+    // These properties track individual system server boot events, and are reset once the boot
+    // threshold is met, or the boot loop trigger window is exceeded between boot events.
     private static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
     private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
 
+    // These properties track multiple calls made to observers tracking boot loops. They are reset
+    // when the de-escalation window is exceeded between boot events.
+    private static final String PROP_BOOT_MITIGATION_WINDOW_START = "sys.boot_mitigation_start";
+    private static final String PROP_BOOT_MITIGATION_COUNT = "sys.boot_mitigation_count";
+
     private long mNumberOfNativeCrashPollsRemaining;
 
     private static final int DB_VERSION = 1;
@@ -191,7 +197,6 @@
     @FunctionalInterface
     @VisibleForTesting
     interface SystemClock {
-        // TODO: Add elapsedRealtime to this interface
         long uptimeMillis();
     }
 
@@ -471,13 +476,14 @@
         synchronized (mLock) {
             if (mBootThreshold.incrementAndTest()) {
                 mBootThreshold.reset();
+                int mitigationCount = mBootThreshold.getMitigationCount() + 1;
                 PackageHealthObserver currentObserverToNotify = null;
                 int currentObserverImpact = Integer.MAX_VALUE;
                 for (int i = 0; i < mAllObservers.size(); i++) {
                     final ObserverInternal observer = mAllObservers.valueAt(i);
                     PackageHealthObserver registeredObserver = observer.registeredObserver;
                     if (registeredObserver != null) {
-                        int impact = registeredObserver.onBootLoop();
+                        int impact = registeredObserver.onBootLoop(mitigationCount);
                         if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
                                 && impact < currentObserverImpact) {
                             currentObserverToNotify = registeredObserver;
@@ -486,7 +492,8 @@
                     }
                 }
                 if (currentObserverToNotify != null) {
-                    currentObserverToNotify.executeBootLoopMitigation();
+                    mBootThreshold.setMitigationCount(mitigationCount);
+                    currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
                 }
             }
         }
@@ -609,15 +616,20 @@
         /**
          * Called when the system server has booted several times within a window of time, defined
          * by {@link #mBootThreshold}
+         *
+         * @param mitigationCount the number of times mitigation has been attempted for this
+         *                        boot loop (including this time).
          */
-        default @PackageHealthObserverImpact int onBootLoop() {
+        default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) {
             return PackageHealthObserverImpact.USER_IMPACT_NONE;
         }
 
         /**
          * Executes mitigation for {@link #onBootLoop}
+         * @param mitigationCount the number of times mitigation has been attempted for this
+         *                        boot loop (including this time).
          */
-        default boolean executeBootLoopMitigation() {
+        default boolean executeBootLoopMitigation(int mitigationCount) {
             return false;
         }
 
@@ -1031,7 +1043,7 @@
                 TypedXmlSerializer out = Xml.resolveSerializer(stream);
                 out.startDocument(null, true);
                 out.startTag(null, TAG_PACKAGE_WATCHDOG);
-                out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+                out.attributeInt(null, ATTR_VERSION, DB_VERSION);
                 for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
                     mAllObservers.valueAt(oIndex).writeLocked(out);
                 }
@@ -1095,7 +1107,7 @@
          * Does not persist any package failure thresholds.
          */
         @GuardedBy("mLock")
-        public boolean writeLocked(XmlSerializer out) {
+        public boolean writeLocked(TypedXmlSerializer out) {
             try {
                 out.startTag(null, TAG_OBSERVER);
                 out.attribute(null, ATTR_NAME, name);
@@ -1213,7 +1225,7 @@
          * #loadFromFile which in turn is only called on construction of the
          * singleton PackageWatchdog.
          **/
-        public static ObserverInternal read(XmlPullParser parser, PackageWatchdog watchdog) {
+        public static ObserverInternal read(TypedXmlPullParser parser, PackageWatchdog watchdog) {
             String observerName = null;
             if (TAG_OBSERVER.equals(parser.getName())) {
                 observerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -1228,14 +1240,14 @@
                 while (XmlUtils.nextElementWithin(parser, innerDepth)) {
                     if (TAG_PACKAGE.equals(parser.getName())) {
                         try {
-                            String packageName = parser.getAttributeValue(null, ATTR_NAME);
-                            long duration = Long.parseLong(
-                                    parser.getAttributeValue(null, ATTR_DURATION));
-                            long healthCheckDuration = Long.parseLong(
-                                    parser.getAttributeValue(null,
-                                            ATTR_EXPLICIT_HEALTH_CHECK_DURATION));
-                            boolean hasPassedHealthCheck = Boolean.parseBoolean(
-                                    parser.getAttributeValue(null, ATTR_PASSED_HEALTH_CHECK));
+                            String packageName = parser.getAttributeValue(
+                                    null, ATTR_NAME);
+                            long duration = parser.getAttributeLong(
+                                    null, ATTR_DURATION);
+                            long healthCheckDuration = parser.getAttributeLong(
+                                    null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
+                            boolean hasPassedHealthCheck = parser.getAttributeBoolean(
+                                    null, ATTR_PASSED_HEALTH_CHECK, false);
                             MonitoredPackage pkg = watchdog.newMonitoredPackage(packageName,
                                     duration, healthCheckDuration, hasPassedHealthCheck);
                             if (pkg != null) {
@@ -1352,14 +1364,12 @@
 
         /** Writes the salient fields to disk using {@code out}. */
         @GuardedBy("mLock")
-        public void writeLocked(XmlSerializer out) throws IOException {
+        public void writeLocked(TypedXmlSerializer out) throws IOException {
             out.startTag(null, TAG_PACKAGE);
             out.attribute(null, ATTR_NAME, getName());
-            out.attribute(null, ATTR_DURATION, String.valueOf(mDurationMs));
-            out.attribute(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION,
-                    String.valueOf(mHealthCheckDurationMs));
-            out.attribute(null, ATTR_PASSED_HEALTH_CHECK,
-                    String.valueOf(mHasPassedHealthCheck));
+            out.attributeLong(null, ATTR_DURATION, mDurationMs);
+            out.attributeLong(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION, mHealthCheckDurationMs);
+            out.attributeBoolean(null, ATTR_PASSED_HEALTH_CHECK, mHasPassedHealthCheck);
             out.endTag(null, TAG_PACKAGE);
         }
 
@@ -1577,7 +1587,7 @@
     /**
      * Handles the thresholding logic for system server boots.
      */
-    static class BootThreshold {
+    class BootThreshold {
 
         private final int mBootTriggerCount;
         private final long mTriggerWindow;
@@ -1604,18 +1614,44 @@
             return SystemProperties.getLong(PROP_RESCUE_BOOT_START, 0);
         }
 
-        public void setStart(long start) {
-            final long now = android.os.SystemClock.elapsedRealtime();
-            final long newStart = MathUtils.constrain(start, 0, now);
-            SystemProperties.set(PROP_RESCUE_BOOT_START, Long.toString(newStart));
+        public int getMitigationCount() {
+            return SystemProperties.getInt(PROP_BOOT_MITIGATION_COUNT, 0);
         }
 
+        public void setStart(long start) {
+            setPropertyStart(PROP_RESCUE_BOOT_START, start);
+        }
+
+        public void setMitigationStart(long start) {
+            setPropertyStart(PROP_BOOT_MITIGATION_WINDOW_START, start);
+        }
+
+        public long getMitigationStart() {
+            return SystemProperties.getLong(PROP_BOOT_MITIGATION_WINDOW_START, 0);
+        }
+
+        public void setMitigationCount(int count) {
+            SystemProperties.set(PROP_BOOT_MITIGATION_COUNT, Integer.toString(count));
+        }
+
+        public void setPropertyStart(String property, long start) {
+            final long now = mSystemClock.uptimeMillis();
+            final long newStart = MathUtils.constrain(start, 0, now);
+            SystemProperties.set(property, Long.toString(newStart));
+        }
+
+
         /** Increments the boot counter, and returns whether the device is bootlooping. */
         public boolean incrementAndTest() {
-            final long now = android.os.SystemClock.elapsedRealtime();
+            final long now = mSystemClock.uptimeMillis();
             if (now - getStart() < 0) {
                 Slog.e(TAG, "Window was less than zero. Resetting start to current time.");
                 setStart(now);
+                setMitigationStart(now);
+            }
+            if (now - getMitigationStart() > DEFAULT_DEESCALATION_WINDOW_MS) {
+                setMitigationCount(0);
+                setMitigationStart(now);
             }
             final long window = now - getStart();
             if (window >= mTriggerWindow) {
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index d04949a..a1cf816 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import static android.provider.DeviceConfig.Properties;
+
 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
 
 import android.annotation.NonNull;
@@ -29,7 +31,6 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
-import android.os.Process;
 import android.os.RecoverySystem;
 import android.os.RemoteCallback;
 import android.os.SystemClock;
@@ -37,10 +38,10 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.ExceptionUtils;
 import android.util.Log;
-import android.util.MathUtils;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -75,8 +76,6 @@
 public class RescueParty {
     @VisibleForTesting
     static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
-    @VisibleForTesting
-    static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
     static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset";
     static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted";
     @VisibleForTesting
@@ -97,6 +96,12 @@
     static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
     @VisibleForTesting
     static final int DEVICE_CONFIG_RESET_MODE = Settings.RESET_MODE_TRUSTED_DEFAULTS;
+    // The DeviceConfig namespace containing all RescueParty switches.
+    @VisibleForTesting
+    static final String NAMESPACE_CONFIGURATION = "configuration";
+    @VisibleForTesting
+    static final String NAMESPACE_TO_PACKAGE_MAPPING_FLAG =
+            "namespace_to_package_mapping";
 
     private static final String NAME = "rescue-party-observer";
 
@@ -107,8 +112,6 @@
             "persist.device_config.configuration.disable_rescue_party";
     private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
             "persist.device_config.configuration.disable_rescue_party_factory_reset";
-    // The DeviceConfig namespace containing all RescueParty switches.
-    private static final String NAMESPACE_CONFIGURATION = "configuration";
 
     private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
             | ApplicationInfo.FLAG_SYSTEM;
@@ -168,13 +171,87 @@
      */
     public static void onSettingsProviderPublished(Context context) {
         handleNativeRescuePartyResets();
-        executeRescueLevel(context, /*failedPackage=*/ null);
         ContentResolver contentResolver = context.getContentResolver();
         Settings.Config.registerMonitorCallback(contentResolver, new RemoteCallback(result -> {
             handleMonitorCallback(context, result);
         }));
     }
 
+
+    /**
+     * Called when {@code RollbackManager} performs Mainline module rollbacks,
+     * to avoid rolled back modules consuming flag values only expected to work
+     * on modules of newer versions.
+     */
+    public static void resetDeviceConfigForPackages(List<String> packageNames) {
+        if (packageNames == null) {
+            return;
+        }
+        Set<String> namespacesToReset = new ArraySet<String>();
+        Iterator<String> it = packageNames.iterator();
+        RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated();
+        // Get runtime package to namespace mapping if created.
+        if (rescuePartyObserver != null) {
+            while (it.hasNext()) {
+                String packageName = it.next();
+                Set<String> runtimeAffectedNamespaces =
+                        rescuePartyObserver.getAffectedNamespaceSet(packageName);
+                if (runtimeAffectedNamespaces != null) {
+                    namespacesToReset.addAll(runtimeAffectedNamespaces);
+                }
+            }
+        }
+        // Get preset package to namespace mapping if created.
+        Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages(
+                packageNames);
+        if (presetAffectedNamespaces != null) {
+            namespacesToReset.addAll(presetAffectedNamespaces);
+        }
+
+        // Clear flags under the namespaces mapped to these packages.
+        // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set.
+        Iterator<String> namespaceIt = namespacesToReset.iterator();
+        while (namespaceIt.hasNext()) {
+            String namespaceToReset = namespaceIt.next();
+            Properties properties = new Properties.Builder(namespaceToReset).build();
+            try {
+                DeviceConfig.setProperties(properties);
+            } catch (DeviceConfig.BadConfigException exception) {
+                logCriticalInfo(Log.WARN, "namespace " + namespaceToReset
+                        + " is already banned, skip reset.");
+            }
+        }
+    }
+
+    private static Set<String> getPresetNamespacesForPackages(List<String> packageNames) {
+        Set<String> resultSet = new ArraySet<String>();
+        try {
+            String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION,
+                    NAMESPACE_TO_PACKAGE_MAPPING_FLAG, "");
+            String[] mappingEntries = flagVal.split(",");
+            for (int i = 0; i < mappingEntries.length; i++) {
+                if (TextUtils.isEmpty(mappingEntries[i])) {
+                    continue;
+                }
+                String[] splittedEntry = mappingEntries[i].split(":");
+                if (splittedEntry.length != 2) {
+                    throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]);
+                }
+                String namespace = splittedEntry[0];
+                String packageName = splittedEntry[1];
+
+                if (packageNames.contains(packageName)) {
+                    resultSet.add(namespace);
+                }
+            }
+        } catch (Exception e) {
+            resultSet.clear();
+            Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e);
+        } finally {
+            return resultSet;
+        }
+    }
+
     @VisibleForTesting
     static long getElapsedRealtime() {
         return SystemClock.elapsedRealtime();
@@ -260,33 +337,6 @@
         }
     }
 
-    /**
-     * Get the next rescue level. This indicates the next level of mitigation that may be taken.
-     */
-    private static int getNextRescueLevel() {
-        return MathUtils.constrain(SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
-                LEVEL_NONE, getMaxRescueLevel());
-    }
-
-    /**
-     * Escalate to the next rescue level. After incrementing the level you'll
-     * probably want to call {@link #executeRescueLevel(Context, String)}.
-     */
-    private static void incrementRescueLevel(int triggerUid) {
-        final int level = getNextRescueLevel();
-        SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
-
-        EventLogTags.writeRescueLevel(level, triggerUid);
-        logCriticalInfo(Log.WARN, "Incremented rescue level to "
-                + levelToString(level) + " triggered by UID " + triggerUid);
-    }
-
-    private static void executeRescueLevel(Context context, @Nullable String failedPackage) {
-        final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
-        if (level == LEVEL_NONE) return;
-        executeRescueLevel(context, failedPackage, level);
-    }
-
     private static void executeRescueLevel(Context context, @Nullable String failedPackage,
             int level) {
         Slog.w(TAG, "Attempting rescue level " + levelToString(level));
@@ -501,6 +551,14 @@
             }
         }
 
+        /** Gets singleton instance. It returns null if the instance is not created yet.*/
+        @Nullable
+        public static RescuePartyObserver getInstanceIfCreated() {
+            synchronized (RescuePartyObserver.class) {
+                return sRescuePartyObserver;
+            }
+        }
+
         @VisibleForTesting
         static void reset() {
             synchronized (RescuePartyObserver.class) {
@@ -561,20 +619,19 @@
         }
 
         @Override
-        public int onBootLoop() {
+        public int onBootLoop(int mitigationCount) {
             if (isDisabled()) {
                 return PackageHealthObserverImpact.USER_IMPACT_NONE;
             }
-            return mapRescueLevelToUserImpact(getNextRescueLevel());
+            return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
         }
 
         @Override
-        public boolean executeBootLoopMitigation() {
+        public boolean executeBootLoopMitigation(int mitigationCount) {
             if (isDisabled()) {
                 return false;
             }
-            incrementRescueLevel(Process.ROOT_UID);
-            executeRescueLevel(mContext, /*failedPackage=*/ null);
+            executeRescueLevel(mContext, /*failedPackage=*/ null, getRescueLevel(mitigationCount));
             return true;
         }
 
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 2455e76..d30e9fb 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -107,7 +107,7 @@
                     TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream);
                     serializer.startDocument(null, true);
                     serializer.startTag(null, XML_TAG_SENSOR_PRIVACY);
-                    serializer.attribute(null, XML_ATTRIBUTE_ENABLED, String.valueOf(enable));
+                    serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enable);
                     serializer.endTag(null, XML_TAG_SENSOR_PRIVACY);
                     serializer.endDocument();
                     mAtomicFile.finishWrite(outputStream);
@@ -180,7 +180,7 @@
                     TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream);
                     serializer.startDocument(null, true);
                     serializer.startTag(null, XML_TAG_SENSOR_PRIVACY);
-                    serializer.attribute(null, XML_ATTRIBUTE_ENABLED, String.valueOf(mEnabled));
+                    serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, mEnabled);
                     serializer.endTag(null, XML_TAG_SENSOR_PRIVACY);
                     serializer.endDocument();
                     mAtomicFile.finishWrite(outputStream);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 8033ce7..dbd27af 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -38,13 +38,8 @@
 import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
 import static android.os.storage.OnObbStateChangeListener.MOUNTED;
 import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
-import static android.os.storage.StorageManager.PROP_FORCED_SCOPED_STORAGE_WHITELIST;
 
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
 import static com.android.internal.util.XmlUtils.readStringAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -144,7 +139,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.HexDump;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -160,9 +154,7 @@
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -172,7 +164,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.spec.KeySpec;
 import java.util.ArrayList;
@@ -186,7 +177,6 @@
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -212,21 +202,34 @@
     private static final String ZRAM_ENABLED_PROPERTY =
             "persist.sys.zram_enabled";
 
-    private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();
-
     // A system property to control if obb app data isolation is enabled in vold.
     private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
             "persist.sys.vold_app_data_isolation_enabled";
 
+    // TODO(b/169327180): Will be fetched from the server, but for now, we emulate this in
+    // the system_server since it can write to DeviceConfig and MediaProvider can read it
+    private static final String PROP_TRANSCODE_ENABLED = "transcode_enabled";
+    private static final String PROP_TRANSCODE_DEFAULT = "transcode_default";
+    private static final String PROP_TRANSCODE_COMPAT_MANIFEST = "transcode_compat_manifest";
+    private static final boolean TRANSCODE_ENABLED_VALUE = false;
+    // Determines the default behavior of apps when transcode is enabled, AKA, Option A/Option B.
+    // If true, transcode by default (Option B). If false, don't transcode by default (Option A)
+    // For dogfood, we go with Option B
+    private static final boolean TRANSCODE_DEFAULT_VALUE = true;
+    // Format is <package_name>,<media_capability_bit_mask>,...
+    // media_capability_bit_mask is defined in MediaProvider/../TranscodeHelper.java:
+    // FLAG_HEVC = 1 << 0;
+    // FLAG_SLOW_MOTION = 1 << 1;
+    // FLAG_HDR_10 = 1 << 2;
+    // FLAG_HDR_10_PLUS = 1 << 3;
+    // FLAG_HDR_HLG = 1 << 4;
+    // FLAG_HDR_DOLBY_VISION = 1 << 5;
+    private static final String TRANSCODE_COMPAT_MANIFEST_VALUE =
+            "com.google.android.apps.photos,1";
+
     // How long we wait to reset storage, if we failed to call onMount on the
     // external storage service.
     public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10;
-    /**
-     * If {@code 1}, enables the isolated storage feature. If {@code -1},
-     * disables the isolated storage feature. If {@code 0}, uses the default
-     * value from the build system.
-     */
-    private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
 
     @GuardedBy("mLock")
     private final Set<Integer> mFuseMountedUser = new ArraySet<>();
@@ -898,22 +901,18 @@
                     com.android.internal.R.bool.config_zramWriteback)) {
             ZramWriteback.scheduleZramWriteback(mContext);
         }
-        // Toggle isolated-enable system property in response to settings
-        mContext.getContentResolver().registerContentObserver(
-            Settings.Global.getUriFor(Settings.Global.ISOLATED_STORAGE_REMOTE),
-            false /*notifyForDescendants*/,
-            new ContentObserver(null /* current thread */) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    refreshIsolatedStorageSettings();
-                }
-            });
-        // For now, simply clone property when it changes
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
-                mContext.getMainExecutor(), (properties) -> {
-                    refreshIsolatedStorageSettings();
-                });
-        refreshIsolatedStorageSettings();
+
+        // TODO(b/169327180): Remove after setting up server-side DeviceConfig flags
+        // Set DeviceConfig values for transcoding that will be read by MediaProvider
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                PROP_TRANSCODE_ENABLED, String.valueOf(TRANSCODE_ENABLED_VALUE),
+                false /* makeDefault */);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                PROP_TRANSCODE_DEFAULT, String.valueOf(TRANSCODE_DEFAULT_VALUE),
+                false /* makeDefault */);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                PROP_TRANSCODE_COMPAT_MANIFEST, TRANSCODE_COMPAT_MANIFEST_VALUE,
+                false /* makeDefault */);
     }
 
     /**
@@ -945,38 +944,6 @@
         }
     }
 
-    private void refreshIsolatedStorageSettings() {
-        // Always copy value from newer DeviceConfig location
-        Settings.Global.putString(mResolver,
-                Settings.Global.ISOLATED_STORAGE_REMOTE,
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
-                        ISOLATED_STORAGE_ENABLED));
-
-        final int local = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
-        final int remote = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ISOLATED_STORAGE_REMOTE, 0);
-
-        // Walk down precedence chain; we prefer local settings first, then
-        // remote settings, before finally falling back to hard-coded default.
-        final boolean res;
-        if (local == -1) {
-            res = false;
-        } else if (local == 1) {
-            res = true;
-        } else if (remote == -1) {
-            res = false;
-        } else if (remote == 1) {
-            res = true;
-        } else {
-            res = true;
-        }
-
-        Slog.d(TAG, "Isolated storage local flag " + local + " and remote flag "
-                + remote + " resolved to " + res);
-        SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
-    }
-
     /**
      * MediaProvider has a ton of code that makes assumptions about storage
      * paths never changing, so we outright kill them to pick up new state.
@@ -1345,12 +1312,13 @@
                     final int oldState = vol.state;
                     final int newState = state;
                     vol.state = newState;
+                    final VolumeInfo vInfo = new VolumeInfo(vol);
                     final SomeArgs args = SomeArgs.obtain();
-                    args.arg1 = vol;
+                    args.arg1 = vInfo;
                     args.arg2 = oldState;
                     args.arg3 = newState;
                     mHandler.obtainMessage(H_VOLUME_STATE_CHANGED, args).sendToTarget();
-                    onVolumeStateChangedLocked(vol, oldState, newState);
+                    onVolumeStateChangedLocked(vInfo, oldState, newState);
                 }
             }
         }
@@ -1762,11 +1730,6 @@
      */
     public StorageManagerService(Context context) {
         sSelf = this;
-
-        // Snapshot feature flag used for this boot
-        SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
-                SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
-
         mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
                 ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
         mContext = context;
@@ -2032,7 +1995,7 @@
                 if (type == START_TAG) {
                     final String tag = in.getName();
                     if (TAG_VOLUMES.equals(tag)) {
-                        final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
+                        final int version = in.getAttributeInt(null, ATTR_VERSION, VERSION_INIT);
                         final boolean primaryPhysical = SystemProperties.getBoolean(
                                 StorageManager.PROP_PRIMARY_PHYSICAL, false);
                         final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
@@ -2067,7 +2030,7 @@
             TypedXmlSerializer out = Xml.resolveSerializer(fos);
             out.startDocument(null, true);
             out.startTag(null, TAG_VOLUMES);
-            writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
+            out.attributeInt(null, ATTR_VERSION, VERSION_FIX_PRIMARY);
             writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
             final int size = mRecords.size();
             for (int i = 0; i < size; i++) {
@@ -2085,31 +2048,33 @@
         }
     }
 
-    public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
-        final int type = readIntAttribute(in, ATTR_TYPE);
+    public static VolumeRecord readVolumeRecord(TypedXmlPullParser in)
+            throws IOException, XmlPullParserException {
+        final int type = in.getAttributeInt(null, ATTR_TYPE);
         final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
         final VolumeRecord meta = new VolumeRecord(type, fsUuid);
         meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
         meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
-        meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
-        meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS, 0);
-        meta.lastSeenMillis = readLongAttribute(in, ATTR_LAST_SEEN_MILLIS, 0);
-        meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS, 0);
-        meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS, 0);
+        meta.userFlags = in.getAttributeInt(null, ATTR_USER_FLAGS);
+        meta.createdMillis = in.getAttributeLong(null, ATTR_CREATED_MILLIS, 0);
+        meta.lastSeenMillis = in.getAttributeLong(null, ATTR_LAST_SEEN_MILLIS, 0);
+        meta.lastTrimMillis = in.getAttributeLong(null, ATTR_LAST_TRIM_MILLIS, 0);
+        meta.lastBenchMillis = in.getAttributeLong(null, ATTR_LAST_BENCH_MILLIS, 0);
         return meta;
     }
 
-    public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
+    public static void writeVolumeRecord(TypedXmlSerializer out, VolumeRecord rec)
+            throws IOException {
         out.startTag(null, TAG_VOLUME);
-        writeIntAttribute(out, ATTR_TYPE, rec.type);
+        out.attributeInt(null, ATTR_TYPE, rec.type);
         writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
         writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
         writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
-        writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
-        writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
-        writeLongAttribute(out, ATTR_LAST_SEEN_MILLIS, rec.lastSeenMillis);
-        writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
-        writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
+        out.attributeInt(null, ATTR_USER_FLAGS, rec.userFlags);
+        out.attributeLong(null, ATTR_CREATED_MILLIS, rec.createdMillis);
+        out.attributeLong(null, ATTR_LAST_SEEN_MILLIS, rec.lastSeenMillis);
+        out.attributeLong(null, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
+        out.attributeLong(null, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
         out.endTag(null, TAG_VOLUME);
     }
 
@@ -2604,32 +2569,6 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
-
-        if ((mask & (StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON
-                | StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF)) != 0) {
-            final int value;
-            if ((flags & StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON) != 0) {
-                value = 1;
-            } else if ((flags & StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF) != 0) {
-                value = -1;
-            } else {
-                value = 0;
-            }
-
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Settings.Global.putInt(mContext.getContentResolver(),
-                        Settings.Global.ISOLATED_STORAGE_LOCAL, value);
-                refreshIsolatedStorageSettings();
-
-                // Perform hard reboot to kick policy into place
-                mHandler.post(() -> {
-                    mContext.getSystemService(PowerManager.class).reboot(null);
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
     }
 
     @Override
@@ -3213,6 +3152,9 @@
             try {
                 mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
                         encodeBytes(secret));
+            } catch (ServiceSpecificException sse) {
+                Slog.d(TAG, "Expected if the user has not unlocked the device.", sse);
+                return;
             } catch (Exception e) {
                 Slog.wtf(TAG, e);
                 return;
@@ -4146,15 +4088,6 @@
         }
     }
 
-    private int getMountMode(int uid, String packageName) {
-        final int mode = getMountModeInternal(uid, packageName);
-        if (LOCAL_LOGV) {
-            Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
-                    + UserHandle.formatUid(uid));
-        }
-        return mode;
-    }
-
     private int getMountModeInternal(int uid, String packageName) {
         try {
             // Get some easy cases out of the way first
@@ -4395,17 +4328,6 @@
             pw.println();
             pw.println("Local unlocked users: " + mLocalUnlockedUsers);
             pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
-
-            final ContentResolver cr = mContext.getContentResolver();
-            pw.println();
-            pw.println("Isolated storage, local feature flag: "
-                    + Settings.Global.getInt(cr, Settings.Global.ISOLATED_STORAGE_LOCAL, 0));
-            pw.println("Isolated storage, remote feature flag: "
-                    + Settings.Global.getInt(cr, Settings.Global.ISOLATED_STORAGE_REMOTE, 0));
-            pw.println("Isolated storage, resolved: " + StorageManager.hasIsolatedStorage());
-            pw.println("Forced scoped storage app list: "
-                    + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
-                    PROP_FORCED_SCOPED_STORAGE_WHITELIST));
             pw.println("isAutomotive:" + mIsAutomotive);
         }
 
@@ -4457,20 +4379,10 @@
     }
 
     private final class StorageManagerInternalImpl extends StorageManagerInternal {
-        // Not guarded by a lock.
-        private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
-                new CopyOnWriteArrayList<>();
-
         @GuardedBy("mResetListeners")
         private final List<StorageManagerInternal.ResetListener> mResetListeners =
                 new ArrayList<>();
 
-        @Override
-        public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
-            // No locking - CopyOnWriteArrayList
-            mPolicies.add(policy);
-        }
-
         /**
          * Check if fuse is running in target user, if it's running then setup its storage dirs.
          * Return true if storage dirs are mounted.
@@ -4515,30 +4427,12 @@
 
         @Override
         public int getExternalStorageMountMode(int uid, String packageName) {
-            if (ENABLE_ISOLATED_STORAGE) {
-                return getMountMode(uid, packageName);
+            final int mode = getMountModeInternal(uid, packageName);
+            if (LOCAL_LOGV) {
+                Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
+                        + UserHandle.formatUid(uid));
             }
-            try {
-                if (packageName == null) {
-                    final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
-                    packageName = packagesForUid[0];
-                }
-            } catch (RemoteException e) {
-                // Should not happen - same process
-            }
-            // No locking - CopyOnWriteArrayList
-            int mountMode = Integer.MAX_VALUE;
-            for (ExternalStorageMountPolicy policy : mPolicies) {
-                final int policyMode = policy.getMountMode(uid, packageName);
-                if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
-                    return Zygote.MOUNT_EXTERNAL_NONE;
-                }
-                mountMode = Math.min(mountMode, policyMode);
-            }
-            if (mountMode == Integer.MAX_VALUE) {
-                return Zygote.MOUNT_EXTERNAL_NONE;
-            }
-            return mountMode;
+            return mode;
         }
 
         @Override
@@ -4608,17 +4502,8 @@
             if (uid == Process.SYSTEM_UID) {
                 return true;
             }
-            if (ENABLE_ISOLATED_STORAGE) {
-                return getMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE;
-            }
-            // No locking - CopyOnWriteArrayList
-            for (ExternalStorageMountPolicy policy : mPolicies) {
-                final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
-                if (!policyHasStorage) {
-                    return false;
-                }
-            }
-            return true;
+
+            return getExternalStorageMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE;
         }
 
         private void killAppForOpChange(int code, int uid) {
diff --git a/services/core/java/com/android/server/SystemUpdateManagerService.java b/services/core/java/com/android/server/SystemUpdateManagerService.java
index 61a7d00..fcba9b5 100644
--- a/services/core/java/com/android/server/SystemUpdateManagerService.java
+++ b/services/core/java/com/android/server/SystemUpdateManagerService.java
@@ -201,7 +201,7 @@
 
     // Performs I/O work only, without validating the loaded info.
     @Nullable
-    private PersistableBundle readInfoFileLocked(XmlPullParser parser)
+    private PersistableBundle readInfoFileLocked(TypedXmlPullParser parser)
             throws XmlPullParserException, IOException {
         int type;
         while ((type = parser.next()) != END_DOCUMENT) {
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index ebeec39..95af842 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -29,6 +29,10 @@
         {
             "name": "CtsScopedStorageHostTest",
             "file_patterns": ["StorageManagerService\\.java"]
+        },
+        {
+            "name": "CtsScopedStorageDeviceOnlyTest",
+            "file_patterns": ["StorageManagerService\\.java"]
         }
     ]
 }
diff --git a/services/core/java/com/android/server/UserspaceRebootLogger.java b/services/core/java/com/android/server/UserspaceRebootLogger.java
index 2403b63..89327b5 100644
--- a/services/core/java/com/android/server/UserspaceRebootLogger.java
+++ b/services/core/java/com/android/server/UserspaceRebootLogger.java
@@ -59,7 +59,7 @@
      */
     public static void noteUserspaceRebootWasRequested() {
         if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
-            Slog.wtf(TAG, "Userspace reboot is not supported.");
+            Slog.wtf(TAG, "noteUserspaceRebootWasRequested: Userspace reboot is not supported.");
             return;
         }
 
@@ -77,7 +77,7 @@
      */
     public static void noteUserspaceRebootSuccess() {
         if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
-            Slog.wtf(TAG, "Userspace reboot is not supported.");
+            Slog.wtf(TAG, "noteUserspaceRebootSuccess: Userspace reboot is not supported.");
             return;
         }
 
@@ -88,11 +88,11 @@
     /**
      * Returns {@code true} if {@code UserspaceRebootReported} atom should be logged.
      *
-     * <p>This call should only be made on devices supporting userspace reboot.
+     * <p>On devices that do not support userspace reboot this method will always return {@code
+     * false}.
      */
     public static boolean shouldLogUserspaceRebootEvent() {
         if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
-            Slog.wtf(TAG, "Userspace reboot is not supported.");
             return false;
         }
 
@@ -110,7 +110,7 @@
      */
     public static void logEventAsync(boolean userUnlocked, Executor executor) {
         if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
-            Slog.wtf(TAG, "Userspace reboot is not supported.");
+            Slog.wtf(TAG, "logEventAsync: Userspace reboot is not supported.");
             return;
         }
 
diff --git a/services/core/java/com/android/server/VibratorManagerService.java b/services/core/java/com/android/server/VibratorManagerService.java
index 356cd0c..f1f2815 100644
--- a/services/core/java/com/android/server/VibratorManagerService.java
+++ b/services/core/java/com/android/server/VibratorManagerService.java
@@ -159,7 +159,7 @@
                 pw.println("    Prints this help text.");
                 pw.println("");
                 pw.println("  list");
-                pw.println("    Prints the id of device vibrators. This do not include any ");
+                pw.println("    Prints the id of device vibrators. This does not include any ");
                 pw.println("    connected input device.");
                 pw.println("");
             }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 63fba25..db2b4e4 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -16,8 +16,6 @@
 
 package com.android.server;
 
-import static android.os.VibrationEffect.Composition.PrimitiveEffect;
-
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
@@ -28,8 +26,6 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.res.Resources;
-import android.hardware.input.InputManager;
 import android.hardware.vibrator.IVibrator;
 import android.os.BatteryStats;
 import android.os.Binder;
@@ -45,7 +41,6 @@
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.Process;
-import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -60,38 +55,33 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
-import android.view.InputDevice;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.vibrator.InputDeviceDelegate;
+import com.android.server.vibrator.Vibration;
 import com.android.server.vibrator.VibrationScaler;
 import com.android.server.vibrator.VibrationSettings;
-
-import libcore.util.NativeAllocationRegistry;
+import com.android.server.vibrator.VibratorController;
+import com.android.server.vibrator.VibratorController.OnVibrationCompleteListener;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class VibratorService extends IVibratorService.Stub
-        implements InputManager.InputDeviceListener {
+/** System implementation of {@link IVibratorService}. */
+public class VibratorService extends IVibratorService.Stub {
     private static final String TAG = "VibratorService";
-    private static final SimpleDateFormat DEBUG_DATE_FORMAT =
-            new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
     private static final boolean DEBUG = false;
     private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
 
-    private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
-
     // Default vibration attributes. Used when vibration is requested without attributes
     private static final VibrationAttributes DEFAULT_ATTRIBUTES =
             new VibrationAttributes.Builder().build();
@@ -99,22 +89,17 @@
     // Used to generate globally unique vibration ids.
     private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
 
-    private final LinkedList<VibrationInfo> mPreviousRingVibrations;
-    private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
-    private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
-    private final LinkedList<VibrationInfo> mPreviousExternalVibrations;
-    private final LinkedList<VibrationInfo> mPreviousVibrations;
+    private final LinkedList<Vibration.DebugInfo> mPreviousRingVibrations;
+    private final LinkedList<Vibration.DebugInfo> mPreviousNotificationVibrations;
+    private final LinkedList<Vibration.DebugInfo> mPreviousAlarmVibrations;
+    private final LinkedList<Vibration.DebugInfo> mPreviousExternalVibrations;
+    private final LinkedList<Vibration.DebugInfo> mPreviousVibrations;
     private final int mPreviousVibrationsLimit;
-    private final boolean mAllowPriorityVibrationsInLowPowerMode;
-    private final List<Integer> mSupportedEffects;
-    private final List<Integer> mSupportedPrimitives;
-    private final long mCapabilities;
-    private final int mDefaultVibrationAmplitude;
-    private final SparseArray<VibrationEffect> mFallbackEffects;
     private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
     private final WorkSource mTmpWorkSource = new WorkSource();
     private final Handler mH;
     private final Object mLock = new Object();
+    private final VibratorController mVibratorController;
 
     private final Context mContext;
     private final PowerManager.WakeLock mWakeLock;
@@ -122,61 +107,21 @@
     private final IBatteryStats mBatteryStatsService;
     private final String mSystemUiPackage;
     private PowerManagerInternal mPowerManagerInternal;
-    private InputManager mIm;
     private VibrationSettings mVibrationSettings;
     private VibrationScaler mVibrationScaler;
+    private InputDeviceDelegate mInputDeviceDelegate;
 
-    private final NativeWrapper mNativeWrapper;
     private volatile VibrateWaveformThread mThread;
 
-    // mInputDeviceVibrators lock should be acquired after mLock, if both are
-    // to be acquired
-    private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<>();
-    private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
-    private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
-
     @GuardedBy("mLock")
     private Vibration mCurrentVibration;
+    @GuardedBy("mLock")
+    private VibrationDeathRecipient mCurrentVibrationDeathRecipient;
     private int mCurVibUid = -1;
     private ExternalVibrationHolder mCurrentExternalVibration;
-    private boolean mVibratorUnderExternalControl;
     private boolean mLowPowerMode;
-    @GuardedBy("mLock")
-    private boolean mIsVibrating;
-    @GuardedBy("mLock")
-    private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
-            new RemoteCallbackList<>();
     private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
 
-    static native long vibratorInit(OnCompleteListener listener);
-
-    static native long vibratorGetFinalizer();
-
-    static native boolean vibratorExists(long nativeServicePtr);
-
-    static native void vibratorOn(long nativeServicePtr, long milliseconds, long vibrationId);
-
-    static native void vibratorOff(long nativeServicePtr);
-
-    static native void vibratorSetAmplitude(long nativeServicePtr, int amplitude);
-
-    static native int[] vibratorGetSupportedEffects(long nativeServicePtr);
-
-    static native int[] vibratorGetSupportedPrimitives(long nativeServicePtr);
-
-    static native long vibratorPerformEffect(
-            long nativeServicePtr, long effect, long strength, long vibrationId);
-
-    static native void vibratorPerformComposedEffect(long nativeServicePtr,
-            VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
-
-    static native void vibratorSetExternalControl(long nativeServicePtr, boolean enabled);
-
-    static native long vibratorGetCapabilities(long nativeServicePtr);
-    static native void vibratorAlwaysOnEnable(long nativeServicePtr, long id, long effect,
-            long strength);
-    static native void vibratorAlwaysOnDisable(long nativeServicePtr, long id);
-
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
                 int capability) {
@@ -187,118 +132,65 @@
             mProcStatesCache.delete(uid);
         }
 
-        @Override public void onUidActive(int uid) {
+        @Override
+        public void onUidActive(int uid) {
         }
 
-        @Override public void onUidIdle(int uid, boolean disabled) {
+        @Override
+        public void onUidIdle(int uid, boolean disabled) {
         }
 
-        @Override public void onUidCachedChanged(int uid, boolean cached) {
+        @Override
+        public void onUidCachedChanged(int uid, boolean cached) {
         }
     };
 
-    /** Listener for vibration completion callbacks from native. */
-    public interface OnCompleteListener {
+    /**
+     * Implementation of {@link OnVibrationCompleteListener} with a weak reference to this service.
+     */
+    private static final class VibrationCompleteListener implements OnVibrationCompleteListener {
+        private WeakReference<VibratorService> mServiceRef;
 
-        /** Callback triggered when vibration is complete, identified by {@link Vibration#id}. */
-        void onComplete(long vibrationId);
+        VibrationCompleteListener(VibratorService service) {
+            mServiceRef = new WeakReference<>(service);
+        }
+
+        @Override
+        public void onComplete(int vibratorId, long vibrationId) {
+            VibratorService service = mServiceRef.get();
+            if (service != null) {
+                service.onVibrationComplete(vibrationId);
+            }
+        }
     }
 
-    /** Holder for a {@link VibrationEffect}. */
-    private final class Vibration implements IBinder.DeathRecipient {
+    /** Death recipient to bind {@link Vibration}. */
+    private final class VibrationDeathRecipient implements IBinder.DeathRecipient {
 
-        public final IBinder token;
-        // Start time in CLOCK_BOOTTIME base.
-        public final long startTime;
-        public final VibrationAttributes attrs;
-        public final long id;
-        public final int uid;
-        public final String opPkg;
-        public final String reason;
+        private final Vibration mVibration;
 
-        // The actual effect to be played.
-        public VibrationEffect effect;
-        // The original effect that was requested. Typically these two things differ because
-        // the effect was scaled based on the users vibration intensity settings.
-        public VibrationEffect originalEffect;
-        // The scale applied to the original effect.
-        public float scale;
-
-        // Start/end times in unix epoch time. Only to be used for debugging purposes and to
-        // correlate with other system events, any duration calculations should be done use
-        // startTime so as not to be affected by discontinuities created by RTC adjustments.
-        private final long mStartTimeDebug;
-        private long mEndTimeDebug;
-        private VibrationInfo.Status mStatus;
-
-        private Vibration(IBinder token, VibrationEffect effect,
-                VibrationAttributes attrs, int uid, String opPkg, String reason) {
-            this.token = token;
-            this.effect = effect;
-            this.id = mNextVibrationId.getAndIncrement();
-            this.startTime = SystemClock.elapsedRealtime();
-            this.attrs = attrs;
-            this.uid = uid;
-            this.opPkg = opPkg;
-            this.reason = reason;
-            mStartTimeDebug = System.currentTimeMillis();
-            mStatus = VibrationInfo.Status.RUNNING;
+        private VibrationDeathRecipient(Vibration vibration) {
+            mVibration = vibration;
         }
 
         @Override
         public void binderDied() {
             synchronized (mLock) {
-                if (this == mCurrentVibration) {
+                if (mVibration == mCurrentVibration) {
                     if (DEBUG) {
                         Slog.d(TAG, "Vibration finished because binder died, cleaning up");
                     }
-                    doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
+                    doCancelVibrateLocked(Vibration.Status.CANCELLED);
                 }
             }
         }
 
-        public void end(VibrationInfo.Status status) {
-            if (hasEnded()) {
-                // Vibration already ended, keep first ending status set and ignore this one.
-                return;
-            }
-            mStatus = status;
-            mEndTimeDebug = System.currentTimeMillis();
+        private void linkToDeath() throws RemoteException {
+            mVibration.token.linkToDeath(this, 0);
         }
 
-        public boolean hasEnded() {
-            return mStatus != VibrationInfo.Status.RUNNING;
-        }
-
-        public boolean hasTimeoutLongerThan(long millis) {
-            final long duration = effect.getDuration();
-            return duration >= 0 && duration > millis;
-        }
-
-        public boolean isHapticFeedback() {
-            return VibratorService.this.isHapticFeedback(attrs.getUsage());
-        }
-
-        public boolean isNotification() {
-            return VibratorService.this.isNotification(attrs.getUsage());
-        }
-
-        public boolean isRingtone() {
-            return VibratorService.this.isRingtone(attrs.getUsage());
-        }
-
-        public boolean isAlarm() {
-            return VibratorService.this.isAlarm(attrs.getUsage());
-        }
-
-        public boolean isFromSystem() {
-            return uid == Process.SYSTEM_UID || uid == 0 || mSystemUiPackage.equals(opPkg);
-        }
-
-        public VibrationInfo toInfo() {
-            return new VibrationInfo(
-                    mStartTimeDebug, mEndTimeDebug, effect, originalEffect, scale, attrs,
-                    uid, opPkg, reason, mStatus);
+        private void unlinkToDeath() {
+            mVibration.token.unlinkToDeath(this, 0);
         }
     }
 
@@ -310,17 +202,17 @@
 
         private final long mStartTimeDebug;
         private long mEndTimeDebug;
-        private VibrationInfo.Status mStatus;
+        private Vibration.Status mStatus;
 
         private ExternalVibrationHolder(ExternalVibration externalVibration) {
             this.externalVibration = externalVibration;
             this.scale = IExternalVibratorService.SCALE_NONE;
             mStartTimeDebug = System.currentTimeMillis();
-            mStatus = VibrationInfo.Status.RUNNING;
+            mStatus = Vibration.Status.RUNNING;
         }
 
-        public void end(VibrationInfo.Status status) {
-            if (mStatus != VibrationInfo.Status.RUNNING) {
+        public void end(Vibration.Status status) {
+            if (mStatus != Vibration.Status.RUNNING) {
                 // Vibration already ended, keep first ending status set and ignore this one.
                 return;
             }
@@ -328,8 +220,8 @@
             mEndTimeDebug = System.currentTimeMillis();
         }
 
-        public VibrationInfo toInfo() {
-            return new VibrationInfo(
+        public Vibration.DebugInfo getDebugInfo() {
+            return new Vibration.DebugInfo(
                     mStartTimeDebug, mEndTimeDebug, /* effect= */ null, /* originalEffect= */ null,
                     scale, externalVibration.getVibrationAttributes(),
                     externalVibration.getUid(), externalVibration.getPackage(),
@@ -337,176 +229,19 @@
         }
     }
 
-    /** Debug information about vibrations. */
-    private static class VibrationInfo {
-
-        public enum Status {
-            RUNNING,
-            FINISHED,
-            CANCELLED,
-            ERROR_APP_OPS,
-            IGNORED,
-            IGNORED_APP_OPS,
-            IGNORED_BACKGROUND,
-            IGNORED_RINGTONE,
-            IGNORED_UNKNOWN_VIBRATION,
-            IGNORED_UNSUPPORTED,
-            IGNORED_FOR_ALARM,
-            IGNORED_FOR_EXTERNAL,
-            IGNORED_FOR_ONGOING,
-            IGNORED_FOR_POWER,
-            IGNORED_FOR_SETTINGS,
-        }
-
-        private final long mStartTimeDebug;
-        private final long mEndTimeDebug;
-        private final VibrationEffect mEffect;
-        private final VibrationEffect mOriginalEffect;
-        private final float mScale;
-        private final VibrationAttributes mAttrs;
-        private final int mUid;
-        private final String mOpPkg;
-        private final String mReason;
-        private final VibrationInfo.Status mStatus;
-
-        VibrationInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect,
-                VibrationEffect originalEffect, float scale, VibrationAttributes attrs,
-                int uid, String opPkg, String reason, VibrationInfo.Status status) {
-            mStartTimeDebug = startTimeDebug;
-            mEndTimeDebug = endTimeDebug;
-            mEffect = effect;
-            mOriginalEffect = originalEffect;
-            mScale = scale;
-            mAttrs = attrs;
-            mUid = uid;
-            mOpPkg = opPkg;
-            mReason = reason;
-            mStatus = status;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("startTime: ")
-                    .append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug)))
-                    .append(", endTime: ")
-                    .append(mEndTimeDebug == 0 ? null
-                            : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
-                    .append(", status: ")
-                    .append(mStatus.name().toLowerCase())
-                    .append(", effect: ")
-                    .append(mEffect)
-                    .append(", originalEffect: ")
-                    .append(mOriginalEffect)
-                    .append(", scale: ")
-                    .append(String.format("%.2f", mScale))
-                    .append(", attrs: ")
-                    .append(mAttrs)
-                    .append(", uid: ")
-                    .append(mUid)
-                    .append(", opPkg: ")
-                    .append(mOpPkg)
-                    .append(", reason: ")
-                    .append(mReason)
-                    .toString();
-        }
-
-        void dumpProto(ProtoOutputStream proto, long fieldId) {
-            final long token = proto.start(fieldId);
-            proto.write(VibrationProto.START_TIME, mStartTimeDebug);
-            proto.write(VibrationProto.END_TIME, mEndTimeDebug);
-            proto.write(VibrationProto.STATUS, mStatus.ordinal());
-
-            final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
-            proto.write(VibrationAttributesProto.USAGE, mAttrs.getUsage());
-            proto.write(VibrationAttributesProto.AUDIO_USAGE, mAttrs.getAudioUsage());
-            proto.write(VibrationAttributesProto.FLAGS, mAttrs.getFlags());
-            proto.end(attrsToken);
-
-            if (mEffect != null) {
-                dumpEffect(proto, VibrationProto.EFFECT, mEffect);
-            }
-            if (mOriginalEffect != null) {
-                dumpEffect(proto, VibrationProto.ORIGINAL_EFFECT, mOriginalEffect);
-            }
-
-            proto.end(token);
-        }
-
-        private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) {
-            final long token = proto.start(fieldId);
-            if (effect instanceof VibrationEffect.OneShot) {
-                dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect);
-            } else if (effect instanceof VibrationEffect.Waveform) {
-                dumpEffect(proto, VibrationEffectProto.WAVEFORM, (VibrationEffect.Waveform) effect);
-            } else if (effect instanceof VibrationEffect.Prebaked) {
-                dumpEffect(proto, VibrationEffectProto.PREBAKED, (VibrationEffect.Prebaked) effect);
-            } else if (effect instanceof VibrationEffect.Composed) {
-                dumpEffect(proto, VibrationEffectProto.COMPOSED, (VibrationEffect.Composed) effect);
-            }
-            proto.end(token);
-        }
-
-        private void dumpEffect(ProtoOutputStream proto, long fieldId,
-                VibrationEffect.OneShot effect) {
-            final long token = proto.start(fieldId);
-            proto.write(OneShotProto.DURATION, (int) effect.getDuration());
-            proto.write(OneShotProto.AMPLITUDE, effect.getAmplitude());
-            proto.end(token);
-        }
-
-        private void dumpEffect(ProtoOutputStream proto, long fieldId,
-                VibrationEffect.Waveform effect) {
-            final long token = proto.start(fieldId);
-            for (long timing : effect.getTimings()) {
-                proto.write(WaveformProto.TIMINGS, (int) timing);
-            }
-            for (int amplitude : effect.getAmplitudes()) {
-                proto.write(WaveformProto.AMPLITUDES, amplitude);
-            }
-            proto.write(WaveformProto.REPEAT, effect.getRepeatIndex() >= 0);
-            proto.end(token);
-        }
-
-        private void dumpEffect(ProtoOutputStream proto, long fieldId,
-                VibrationEffect.Prebaked effect) {
-            final long token = proto.start(fieldId);
-            proto.write(PrebakedProto.EFFECT_ID, effect.getId());
-            proto.write(PrebakedProto.EFFECT_STRENGTH, effect.getEffectStrength());
-            proto.write(PrebakedProto.FALLBACK, effect.shouldFallback());
-            proto.end(token);
-        }
-
-        private void dumpEffect(ProtoOutputStream proto, long fieldId,
-                VibrationEffect.Composed effect) {
-            final long token = proto.start(fieldId);
-            for (PrimitiveEffect primitive : effect.getPrimitiveEffects()) {
-                proto.write(ComposedProto.EFFECT_IDS, primitive.id);
-                proto.write(ComposedProto.EFFECT_SCALES, primitive.scale);
-                proto.write(ComposedProto.DELAYS, primitive.delay);
-            }
-            proto.end(token);
-        }
-    }
-
     VibratorService(Context context) {
         this(context, new Injector());
     }
 
     @VisibleForTesting
     VibratorService(Context context, Injector injector) {
-        mNativeWrapper = injector.getNativeWrapper();
         mH = injector.createHandler(Looper.myLooper());
-
-        mNativeWrapper.vibratorInit(this::onVibrationComplete);
+        mVibratorController = injector.createVibratorController(
+                new VibrationCompleteListener(this));
 
         // Reset the hardware to a default state, in case this is a runtime
         // restart instead of a fresh boot.
-        mNativeWrapper.vibratorOff();
-
-        mSupportedEffects = asList(mNativeWrapper.vibratorGetSupportedEffects());
-        mSupportedPrimitives = asList(mNativeWrapper.vibratorGetSupportedPrimitives());
-        mCapabilities = mNativeWrapper.vibratorGetCapabilities();
+        mVibratorController.off();
 
         mContext = context;
         PowerManager pm = context.getSystemService(PowerManager.class);
@@ -522,12 +257,6 @@
         mPreviousVibrationsLimit = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
 
-        mDefaultVibrationAmplitude = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_defaultVibrationAmplitude);
-
-        mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
-
         mPreviousRingVibrations = new LinkedList<>();
         mPreviousNotificationVibrations = new LinkedList<>();
         mPreviousAlarmVibrations = new LinkedList<>();
@@ -538,48 +267,15 @@
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         context.registerReceiver(mIntentReceiver, filter);
 
-        VibrationEffect clickEffect = createEffectFromResource(
-                com.android.internal.R.array.config_virtualKeyVibePattern);
-        VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
-                DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
-        VibrationEffect heavyClickEffect = createEffectFromResource(
-                com.android.internal.R.array.config_longPressVibePattern);
-        VibrationEffect tickEffect = createEffectFromResource(
-                com.android.internal.R.array.config_clockTickVibePattern);
-
-        mFallbackEffects = new SparseArray<>();
-        mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
-        mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
-        mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
-        mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
-
-        mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
-                VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
-
         injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
     }
 
-    private VibrationEffect createEffectFromResource(int resId) {
-        long[] timings = getLongIntArray(mContext.getResources(), resId);
-        return createEffectFromTimings(timings);
-    }
-
-    private static VibrationEffect createEffectFromTimings(long[] timings) {
-        if (timings == null || timings.length == 0) {
-            return null;
-        } else if (timings.length == 1) {
-            return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
-        } else {
-            return VibrationEffect.createWaveform(timings, -1);
-        }
-    }
-
     public void systemReady() {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
         try {
-            mIm = mContext.getSystemService(InputManager.class);
             mVibrationSettings = new VibrationSettings(mContext, mH);
             mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
+            mInputDeviceDelegate = new InputDeviceDelegate(mContext, mH);
 
             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
             mPowerManagerInternal.registerLowPowerModeObserver(
@@ -626,14 +322,19 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Vibration finished by callback, cleaning up");
                 }
-                doCancelVibrateLocked(VibrationInfo.Status.FINISHED);
+                doCancelVibrateLocked(Vibration.Status.FINISHED);
             }
         }
     }
 
     @Override // Binder call
     public boolean hasVibrator() {
-        return doVibratorExists();
+        // For now, we choose to ignore the presence of input devices that have vibrators
+        // when reporting whether the device has a vibrator.  Applications often use this
+        // information to decide whether to enable certain features so they expect the
+        // result of hasVibrator() to be constant.  For now, just report whether
+        // the device has a built-in vibrator.
+        return mVibratorController.isAvailable();
     }
 
     @Override // Binder call
@@ -641,32 +342,7 @@
         if (!hasPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE)) {
             throw new SecurityException("Requires ACCESS_VIBRATOR_STATE permission");
         }
-        synchronized (mLock) {
-            return mIsVibrating;
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void notifyStateListenerLocked(IVibratorStateListener listener) {
-        try {
-            listener.onVibrating(mIsVibrating);
-        } catch (RemoteException | RuntimeException e) {
-            Slog.e(TAG, "Vibrator callback failed to call", e);
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void notifyStateListenersLocked() {
-        final int length = mVibratorStateListeners.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                final IVibratorStateListener listener =
-                        mVibratorStateListeners.getBroadcastItem(i);
-                notifyStateListenerLocked(listener);
-            }
-        } finally {
-            mVibratorStateListeners.finishBroadcast();
-        }
+        return mVibratorController.isVibrating();
     }
 
     @Override // Binder call
@@ -674,19 +350,7 @@
         if (!hasPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE)) {
             throw new SecurityException("Requires ACCESS_VIBRATOR_STATE permission");
         }
-        synchronized (mLock) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (!mVibratorStateListeners.register(listener)) {
-                    return false;
-                }
-                // Notify its callback after new client registered.
-                notifyStateListenerLocked(listener);
-                return true;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
+        return mVibratorController.registerVibratorStateListener(listener);
     }
 
     @Override // Binder call
@@ -695,54 +359,26 @@
         if (!hasPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE)) {
             throw new SecurityException("Requires ACCESS_VIBRATOR_STATE permission");
         }
-        synchronized (mLock) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                return mVibratorStateListeners.unregister(listener);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
+        return mVibratorController.unregisterVibratorStateListener(listener);
     }
 
     @Override // Binder call
     public boolean hasAmplitudeControl() {
-        synchronized (mInputDeviceVibrators) {
-            // Input device vibrators don't support amplitude controls yet, but are still used over
-            // the system vibrator when connected.
-            return hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)
-                    && mInputDeviceVibrators.isEmpty();
-        }
+        // Input device vibrators always support amplitude controls.
+        return mInputDeviceDelegate.isAvailable()
+                || mVibratorController.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL);
     }
 
     @Override // Binder call
     public int[] areEffectsSupported(int[] effectIds) {
-        int[] supported = new int[effectIds.length];
-        if (mSupportedEffects == null) {
-            Arrays.fill(supported, Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN);
-        } else {
-            for (int i = 0; i < effectIds.length; i++) {
-                supported[i] = mSupportedEffects.contains(effectIds[i])
-                        ? Vibrator.VIBRATION_EFFECT_SUPPORT_YES
-                        : Vibrator.VIBRATION_EFFECT_SUPPORT_NO;
-            }
-        }
-        return supported;
+        return mVibratorController.areEffectsSupported(effectIds);
     }
 
     @Override // Binder call
     public boolean[] arePrimitivesSupported(int[] primitiveIds) {
-        boolean[] supported = new boolean[primitiveIds.length];
-        if (!hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) || mSupportedPrimitives == null) {
-            return supported;
-        }
-        for (int i = 0; i < primitiveIds.length; i++) {
-            supported[i] = mSupportedPrimitives.contains(primitiveIds[i]);
-        }
-        return supported;
+        return mVibratorController.arePrimitivesSupported(primitiveIds);
     }
 
-
     private static List<Integer> asList(int... vals) {
         if (vals == null) {
             return null;
@@ -760,14 +396,14 @@
         if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) {
             throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission");
         }
-        if (!hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+        if (!mVibratorController.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
             Slog.e(TAG, "Always-on effects not supported.");
             return false;
         }
         if (effect == null) {
             synchronized (mLock) {
                 mAlwaysOnEffects.delete(alwaysOnId);
-                mNativeWrapper.vibratorAlwaysOnDisable(alwaysOnId);
+                mVibratorController.updateAlwaysOn(alwaysOnId, /* effect= */ null);
             }
         } else {
             if (!verifyVibrationEffect(effect)) {
@@ -779,7 +415,8 @@
             }
             attrs = fixupVibrationAttributes(attrs);
             synchronized (mLock) {
-                Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null);
+                Vibration vib = new Vibration(null, mNextVibrationId.getAndIncrement(), effect,
+                        attrs, uid, opPkg, null);
                 mAlwaysOnEffects.put(alwaysOnId, vib);
                 updateAlwaysOnLocked(alwaysOnId, vib);
             }
@@ -839,18 +476,6 @@
         return attrs;
     }
 
-    private static long[] getLongIntArray(Resources r, int resid) {
-        int[] ar = r.getIntArray(resid);
-        if (ar == null) {
-            return null;
-        }
-        long[] out = new long[ar.length];
-        for (int i = 0; i < ar.length; i++) {
-            out[i] = ar[i];
-        }
-        return out;
-    }
-
     @Override // Binder call
     public void vibrate(int uid, String opPkg, VibrationEffect effect,
             @Nullable VibrationAttributes attrs, String reason, IBinder token) {
@@ -869,24 +494,26 @@
             }
 
             attrs = fixupVibrationAttributes(attrs);
-            Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
+            Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
+                    uid, opPkg, reason);
 
             // If our current vibration is longer than the new vibration and is the same amplitude,
             // then just let the current one finish.
             synchronized (mLock) {
+                VibrationEffect currentEffect =
+                        mCurrentVibration == null ? null : mCurrentVibration.getEffect();
                 if (effect instanceof VibrationEffect.OneShot
-                        && mCurrentVibration != null
-                        && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
+                        && currentEffect instanceof VibrationEffect.OneShot) {
                     VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
                     VibrationEffect.OneShot currentOneShot =
-                            (VibrationEffect.OneShot) mCurrentVibration.effect;
-                    if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
+                            (VibrationEffect.OneShot) currentEffect;
+                    if (currentOneShot.getDuration() > newOneShot.getDuration()
                             && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
                         if (DEBUG) {
                             Slog.d(TAG,
                                     "Ignoring incoming vibration in favor of current vibration");
                         }
-                        endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ONGOING);
+                        endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_ONGOING);
                         return;
                     }
                 }
@@ -898,7 +525,7 @@
                     if (DEBUG) {
                         Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
                     }
-                    endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_EXTERNAL);
+                    endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_EXTERNAL);
                     return;
                 }
 
@@ -908,32 +535,32 @@
                 // alarms, in favor of one-shot vibrations that are likely quite short.
                 if (!isRepeatingVibration(effect)
                         && mCurrentVibration != null
-                        && isRepeatingVibration(mCurrentVibration.effect)) {
+                        && isRepeatingVibration(currentEffect)) {
                     if (DEBUG) {
                         Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
                     }
-                    endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ALARM);
+                    endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_ALARM);
                     return;
                 }
 
                 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
                         > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
-                        && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
+                        && !isNotification(vib) && !isRingtone(vib) && !isAlarm(vib)) {
                     Slog.e(TAG, "Ignoring incoming vibration as process with"
                             + " uid= " + uid + " is background,"
                             + " attrs= " + vib.attrs);
-                    endVibrationLocked(vib, VibrationInfo.Status.IGNORED_BACKGROUND);
+                    endVibrationLocked(vib, Vibration.Status.IGNORED_BACKGROUND);
                     return;
                 }
-                linkVibration(vib);
+                linkVibrationLocked(vib);
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
+                    doCancelVibrateLocked(Vibration.Status.CANCELLED);
                     startVibrationLocked(vib);
 
                     if (!vib.hasEnded() && mCurrentVibration.id != vib.id) {
                         // Vibration was unexpectedly ignored: add to list for debugging
-                        endVibrationLocked(vib, VibrationInfo.Status.IGNORED);
+                        endVibrationLocked(vib, Vibration.Status.IGNORED);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -953,13 +580,13 @@
         return effect.getDuration() == Long.MAX_VALUE;
     }
 
-    private void endVibrationLocked(Vibration vib, VibrationInfo.Status status) {
-        final LinkedList<VibrationInfo> previousVibrations;
-        if (vib.isRingtone()) {
+    private void endVibrationLocked(Vibration vib, Vibration.Status status) {
+        final LinkedList<Vibration.DebugInfo> previousVibrations;
+        if (isRingtone(vib)) {
             previousVibrations = mPreviousRingVibrations;
-        } else if (vib.isNotification()) {
+        } else if (isNotification(vib)) {
             previousVibrations = mPreviousNotificationVibrations;
-        } else if (vib.isAlarm()) {
+        } else if (isAlarm(vib)) {
             previousVibrations = mPreviousAlarmVibrations;
         } else {
             previousVibrations = mPreviousVibrations;
@@ -969,15 +596,15 @@
             previousVibrations.removeFirst();
         }
         vib.end(status);
-        previousVibrations.addLast(vib.toInfo());
+        previousVibrations.addLast(vib.getDebugInfo());
     }
 
-    private void endVibrationLocked(ExternalVibrationHolder vib, VibrationInfo.Status status) {
+    private void endVibrationLocked(ExternalVibrationHolder vib, Vibration.Status status) {
         if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) {
             mPreviousExternalVibrations.removeFirst();
         }
         vib.end(status);
-        mPreviousExternalVibrations.addLast(vib.toInfo());
+        mPreviousExternalVibrations.addLast(vib.getDebugInfo());
     }
 
     @Override // Binder call
@@ -993,7 +620,7 @@
                 }
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
+                    doCancelVibrateLocked(Vibration.Status.CANCELLED);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -1002,7 +629,7 @@
     }
 
     @GuardedBy("mLock")
-    private void doCancelVibrateLocked(VibrationInfo.Status status) {
+    private void doCancelVibrateLocked(Vibration.Status status) {
         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
         try {
@@ -1014,7 +641,7 @@
                 endVibrationLocked(mCurrentExternalVibration, status);
                 mCurrentExternalVibration.externalVibration.mute();
                 mCurrentExternalVibration = null;
-                setVibratorUnderExternalControl(false);
+                mVibratorController.setExternalControl(false);
             }
             doVibratorOff();
             reportFinishVibrationLocked(status);
@@ -1031,7 +658,7 @@
         synchronized (mLock) {
             // Make sure the vibration is really done. This also reports that the vibration is
             // finished.
-            doCancelVibrateLocked(VibrationInfo.Status.FINISHED);
+            doCancelVibrateLocked(Vibration.Status.FINISHED);
         }
     }
 
@@ -1055,23 +682,22 @@
         try {
             // Set current vibration before starting it, so callback will work.
             mCurrentVibration = vib;
-            if (vib.effect instanceof VibrationEffect.OneShot) {
+            VibrationEffect effect = vib.getEffect();
+            if (effect instanceof VibrationEffect.OneShot) {
                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
                 doVibratorOn(vib);
-            } else if (vib.effect instanceof VibrationEffect.Waveform) {
-                // mThread better be null here. doCancelVibrate should always be
-                // called before startNextVibrationLocked or startVibrationLocked.
-                mThread = new VibrateWaveformThread(vib);
-                mThread.start();
-            } else if (vib.effect instanceof VibrationEffect.Prebaked) {
+            } else if (effect instanceof VibrationEffect.Waveform) {
+                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+                doVibratorWaveformEffectLocked(vib);
+            } else if (effect instanceof VibrationEffect.Prebaked) {
                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
                 doVibratorPrebakedEffectLocked(vib);
-            } else if (vib.effect instanceof VibrationEffect.Composed) {
+            } else if (effect instanceof VibrationEffect.Composed) {
                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
                 doVibratorComposedEffectLocked(vib);
             } else {
                 Slog.e(TAG, "Unknown vibration type, ignoring");
-                endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNKNOWN_VIBRATION);
+                endVibrationLocked(vib, Vibration.Status.IGNORED_UNKNOWN_VIBRATION);
                 // The set current vibration is not actually playing, so drop it.
                 mCurrentVibration = null;
             }
@@ -1093,11 +719,7 @@
 
     /** Scale the vibration effect by the intensity as appropriate based its intent. */
     private void applyVibrationIntensityScalingLocked(Vibration vib) {
-        VibrationEffect scaled = mVibrationScaler.scale(vib.effect, vib.attrs.getUsage());
-        if (!scaled.equals(vib.effect)) {
-            vib.originalEffect = vib.effect;
-            vib.effect = scaled;
-        }
+        vib.updateEffect(mVibrationScaler.scale(vib.getEffect(), vib.attrs.getUsage()));
     }
 
     private static boolean shouldBypassDnd(VibrationAttributes attrs) {
@@ -1123,21 +745,21 @@
 
     private boolean shouldVibrate(Vibration vib) {
         if (!shouldVibrateForPowerModeLocked(vib)) {
-            endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_POWER);
+            endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_POWER);
             return false;
         }
 
         int intensity = mVibrationSettings.getCurrentIntensity(vib.attrs.getUsage());
         if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
-            endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_SETTINGS);
+            endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_SETTINGS);
             return false;
         }
 
-        if (vib.isRingtone() && !mVibrationSettings.shouldVibrateForRingtone()) {
+        if (isRingtone(vib) && !mVibrationSettings.shouldVibrateForRingtone()) {
             if (DEBUG) {
                 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
             }
-            endVibrationLocked(vib, VibrationInfo.Status.IGNORED_RINGTONE);
+            endVibrationLocked(vib, Vibration.Status.IGNORED_RINGTONE);
             return false;
         }
 
@@ -1147,9 +769,9 @@
                 // We might be getting calls from within system_server, so we don't actually
                 // want to throw a SecurityException here.
                 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
-                endVibrationLocked(vib, VibrationInfo.Status.ERROR_APP_OPS);
+                endVibrationLocked(vib, Vibration.Status.ERROR_APP_OPS);
             } else {
-                endVibrationLocked(vib, VibrationInfo.Status.IGNORED_APP_OPS);
+                endVibrationLocked(vib, Vibration.Status.IGNORED_APP_OPS);
             }
             return false;
         }
@@ -1158,14 +780,14 @@
     }
 
     @GuardedBy("mLock")
-    private void reportFinishVibrationLocked(VibrationInfo.Status status) {
+    private void reportFinishVibrationLocked(Vibration.Status status) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
         try {
             if (mCurrentVibration != null) {
                 endVibrationLocked(mCurrentVibration, status);
                 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
                         mCurrentVibration.opPkg);
-                unlinkVibration(mCurrentVibration);
+                unlinkVibrationLocked();
                 mCurrentVibration = null;
             }
         } finally {
@@ -1173,73 +795,45 @@
         }
     }
 
-    private void linkVibration(Vibration vib) {
+    @GuardedBy("mLock")
+    private void linkVibrationLocked(Vibration vib) {
+        // Unlink previously linked vibration, if any.
+        unlinkVibrationLocked();
         // Only link against waveforms since they potentially don't have a finish if
         // they're repeating. Let other effects just play out until they're done.
-        if (vib.effect instanceof VibrationEffect.Waveform) {
+        if (vib.getEffect() instanceof VibrationEffect.Waveform) {
             try {
-                vib.token.linkToDeath(vib, 0);
+                mCurrentVibrationDeathRecipient = new VibrationDeathRecipient(vib);
+                mCurrentVibrationDeathRecipient.linkToDeath();
             } catch (RemoteException e) {
                 return;
             }
         }
     }
 
-    private void unlinkVibration(Vibration vib) {
-        if (vib.effect instanceof VibrationEffect.Waveform) {
-            vib.token.unlinkToDeath(vib, 0);
+    @GuardedBy("mLock")
+    private void unlinkVibrationLocked() {
+        if (mCurrentVibrationDeathRecipient != null) {
+            mCurrentVibrationDeathRecipient.unlinkToDeath();
+            mCurrentVibrationDeathRecipient = null;
         }
     }
 
     private void updateVibrators() {
         synchronized (mLock) {
-            boolean devicesUpdated = updateInputDeviceVibratorsLocked();
+            boolean devicesUpdated = mInputDeviceDelegate.updateInputDeviceVibrators(
+                    mVibrationSettings.shouldVibrateInputDevices());
             boolean lowPowerModeUpdated = updateLowPowerModeLocked();
 
             if (devicesUpdated || lowPowerModeUpdated) {
                 // If the state changes out from under us then just reset.
-                doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
+                doCancelVibrateLocked(Vibration.Status.CANCELLED);
             }
 
             updateAlwaysOnLocked();
         }
     }
 
-    private boolean updateInputDeviceVibratorsLocked() {
-        boolean changed = false;
-        boolean vibrateInputDevices = mVibrationSettings.shouldVibrateInputDevices();
-        if (vibrateInputDevices != mVibrateInputDevicesSetting) {
-            changed = true;
-            mVibrateInputDevicesSetting = vibrateInputDevices;
-        }
-
-        if (mVibrateInputDevicesSetting) {
-            if (!mInputDeviceListenerRegistered) {
-                mInputDeviceListenerRegistered = true;
-                mIm.registerInputDeviceListener(this, mH);
-            }
-        } else {
-            if (mInputDeviceListenerRegistered) {
-                mInputDeviceListenerRegistered = false;
-                mIm.unregisterInputDeviceListener(this);
-            }
-        }
-
-        mInputDeviceVibrators.clear();
-        if (mVibrateInputDevicesSetting) {
-            int[] ids = mIm.getInputDeviceIds();
-            for (int i = 0; i < ids.length; i++) {
-                InputDevice device = mIm.getInputDevice(ids[i]);
-                Vibrator vibrator = device.getVibrator();
-                if (vibrator.hasVibrator()) {
-                    mInputDeviceVibrators.add(vibrator);
-                }
-            }
-            return true;
-        }
-        return changed;
-    }
-
     private boolean updateLowPowerModeLocked() {
         boolean lowPowerMode = mPowerManagerInternal
                 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
@@ -1251,13 +845,13 @@
     }
 
     private void updateAlwaysOnLocked(int id, Vibration vib) {
+        VibrationEffect.Prebaked effect;
         if (!shouldVibrate(vib)) {
-            mNativeWrapper.vibratorAlwaysOnDisable(id);
+            effect = null;
         } else {
-            VibrationEffect.Prebaked scaled = mVibrationScaler.scale(vib.effect,
-                    vib.attrs.getUsage());
-            mNativeWrapper.vibratorAlwaysOnEnable(id, scaled.getId(), scaled.getEffectStrength());
+            effect = mVibrationScaler.scale(vib.getEffect(), vib.attrs.getUsage());
         }
+        mVibratorController.updateAlwaysOn(id, effect);
     }
 
     private void updateAlwaysOnLocked() {
@@ -1268,85 +862,64 @@
         }
     }
 
-    @Override
-    public void onInputDeviceAdded(int deviceId) {
-        updateVibrators();
-    }
-
-    @Override
-    public void onInputDeviceChanged(int deviceId) {
-        updateVibrators();
-    }
-
-    @Override
-    public void onInputDeviceRemoved(int deviceId) {
-        updateVibrators();
-    }
-
-    private boolean doVibratorExists() {
-        // For now, we choose to ignore the presence of input devices that have vibrators
-        // when reporting whether the device has a vibrator.  Applications often use this
-        // information to decide whether to enable certain features so they expect the
-        // result of hasVibrator() to be constant.  For now, just report whether
-        // the device has a built-in vibrator.
-        //synchronized (mInputDeviceVibrators) {
-        //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
-        //}
-        return mNativeWrapper.vibratorExists();
-    }
-
     private void doVibratorOn(Vibration vib) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
         try {
-            synchronized (mInputDeviceVibrators) {
-                final VibrationEffect.OneShot oneShot = vib.effect.resolve(
-                        mDefaultVibrationAmplitude);
-                if (DEBUG) {
-                    Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms"
-                            + " with amplitude " + oneShot.getAmplitude() + ".");
-                }
+            final VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.getEffect();
+            if (DEBUG) {
+                Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms"
+                        + " with amplitude " + oneShot.getAmplitude() + ".");
+            }
+            boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
+                    vib.uid, vib.opPkg, oneShot, vib.reason, vib.attrs);
+            if (inputDevicesAvailable) {
+                // The set current vibration is no longer being played by this service, so drop it.
+                mCurrentVibration = null;
+                endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
+            } else {
                 noteVibratorOnLocked(vib.uid, oneShot.getDuration());
-                final int vibratorCount = mInputDeviceVibrators.size();
-                if (vibratorCount != 0) {
-                    for (int i = 0; i < vibratorCount; i++) {
-                        mInputDeviceVibrators.get(i).vibrate(vib.uid, vib.opPkg, oneShot,
-                                vib.reason, vib.attrs);
-                    }
-                } else {
-                    // Note: ordering is important here! Many haptic drivers will reset their
-                    // amplitude when enabled, so we always have to enable first, then set the
-                    // amplitude.
-                    mNativeWrapper.vibratorOn(oneShot.getDuration(), vib.id);
-                    doVibratorSetAmplitude(oneShot.getAmplitude());
-                }
+                // Note: ordering is important here! Many haptic drivers will reset their
+                // amplitude when enabled, so we always have to enable first, then set the
+                // amplitude.
+                mVibratorController.on(oneShot.getDuration(), vib.id);
+                mVibratorController.setAmplitude(oneShot.getAmplitude());
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
         }
     }
 
-    private void doVibratorSetAmplitude(int amplitude) {
-        if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
-            mNativeWrapper.vibratorSetAmplitude(amplitude);
-        }
-    }
-
     private void doVibratorOff() {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
         try {
-            synchronized (mInputDeviceVibrators) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Turning vibrator off.");
-                }
-                noteVibratorOffLocked();
-                final int vibratorCount = mInputDeviceVibrators.size();
-                if (vibratorCount != 0) {
-                    for (int i = 0; i < vibratorCount; i++) {
-                        mInputDeviceVibrators.get(i).cancel();
-                    }
-                } else {
-                    mNativeWrapper.vibratorOff();
-                }
+            if (DEBUG) {
+                Slog.d(TAG, "Turning vibrator off.");
+            }
+            noteVibratorOffLocked();
+            boolean inputDevicesAvailable = mInputDeviceDelegate.cancelVibrateIfAvailable();
+            if (!inputDevicesAvailable) {
+                mVibratorController.off();
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void doVibratorWaveformEffectLocked(Vibration vib) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorWaveformEffectLocked");
+        try {
+            boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
+                    vib.uid, vib.opPkg, vib.getEffect(), vib.reason, vib.attrs);
+            if (inputDevicesAvailable) {
+                // The set current vibration is no longer being played by this service, so drop it.
+                mCurrentVibration = null;
+                endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
+            } else {
+                // mThread better be null here. doCancelVibrate should always be
+                // called before startNextVibrationLocked or startVibrationLocked.
+                mThread = new VibrateWaveformThread(vib);
+                mThread.start();
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -1357,37 +930,33 @@
     private void doVibratorPrebakedEffectLocked(Vibration vib) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
         try {
-            final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
-            final boolean usingInputDeviceVibrators;
-            synchronized (mInputDeviceVibrators) {
-                usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
-            }
-            // Input devices don't support prebaked effect, so skip trying it with them.
-            if (!usingInputDeviceVibrators) {
-                long duration = mNativeWrapper.vibratorPerformEffect(
-                        prebaked.getId(), prebaked.getEffectStrength(), vib.id);
+            final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.getEffect();
+            // Input devices don't support prebaked effect, so skip trying it with them and allow
+            // fallback to be attempted.
+            if (!mInputDeviceDelegate.isAvailable()) {
+                long duration = mVibratorController.on(prebaked, vib.id);
                 if (duration > 0) {
                     noteVibratorOnLocked(vib.uid, duration);
                     return;
                 }
             }
-            endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED);
+            endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED);
             // The set current vibration is not actually playing, so drop it.
             mCurrentVibration = null;
 
             if (!prebaked.shouldFallback()) {
                 return;
             }
-            VibrationEffect effect = getFallbackEffect(prebaked.getId());
+            VibrationEffect effect = mVibrationSettings.getFallbackEffect(prebaked.getId());
             if (effect == null) {
                 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
                 return;
             }
-            Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
-                    vib.opPkg, vib.reason + " (fallback)");
+            Vibration fallbackVib = new Vibration(vib.token, mNextVibrationId.getAndIncrement(),
+                    effect, vib.attrs, vib.uid, vib.opPkg, vib.reason + " (fallback)");
             // Set current vibration before starting it, so callback will work.
             mCurrentVibration = fallbackVib;
-            linkVibration(fallbackVib);
+            linkVibrationLocked(fallbackVib);
             applyVibrationIntensityScalingLocked(fallbackVib);
             startVibrationInnerLocked(fallbackVib);
         } finally {
@@ -1400,53 +969,49 @@
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorComposedEffectLocked");
 
         try {
-            final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.effect;
-            final boolean usingInputDeviceVibrators;
-            synchronized (mInputDeviceVibrators) {
-                usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
-            }
-            // Input devices don't support composed effect, so skip trying it with them.
-            if (usingInputDeviceVibrators || !hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
-                endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED);
+            final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.getEffect();
+            boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
+                    vib.uid, vib.opPkg, composed, vib.reason, vib.attrs);
+            if (inputDevicesAvailable) {
+                // The set current vibration is no longer being played by this service, so drop it.
+                mCurrentVibration = null;
+                endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
+                return;
+            } else if (!mVibratorController.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
                 // The set current vibration is not actually playing, so drop it.
                 mCurrentVibration = null;
+                endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED);
                 return;
             }
 
-            PrimitiveEffect[] primitiveEffects =
-                    composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
-            mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib.id);
+            mVibratorController.on(composed, vib.id);
 
             // Composed effects don't actually give us an estimated duration, so we just guess here.
-            noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
+            noteVibratorOnLocked(vib.uid, 10 * composed.getPrimitiveEffects().size());
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
         }
 
     }
 
-    private boolean hasCapability(long capability) {
-        return (mCapabilities & capability) == capability;
+    private static boolean isNotification(Vibration vib) {
+        return vib.attrs.getUsage() == VibrationAttributes.USAGE_NOTIFICATION;
     }
 
-    private VibrationEffect getFallbackEffect(int effectId) {
-        return mFallbackEffects.get(effectId);
+    private static boolean isRingtone(Vibration vib) {
+        return vib.attrs.getUsage() == VibrationAttributes.USAGE_RINGTONE;
     }
 
-    private static boolean isNotification(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
+    private static boolean isHapticFeedback(Vibration vib) {
+        return vib.attrs.getUsage() == VibrationAttributes.USAGE_TOUCH;
     }
 
-    private static boolean isRingtone(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_RINGTONE;
+    private static boolean isAlarm(Vibration vib) {
+        return vib.attrs.getUsage() == VibrationAttributes.USAGE_ALARM;
     }
 
-    private static boolean isHapticFeedback(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_TOUCH;
-    }
-
-    private static boolean isAlarm(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_ALARM;
+    private boolean isFromSystem(Vibration vib) {
+        return vib.uid == Process.SYSTEM_UID || vib.uid == 0 || mSystemUiPackage.equals(vib.opPkg);
     }
 
     private void noteVibratorOnLocked(int uid, long millis) {
@@ -1455,10 +1020,6 @@
             FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED, uid, null,
                     FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
             mCurVibUid = uid;
-            if (!mIsVibrating) {
-                mIsVibrating = true;
-                notifyStateListenersLocked();
-            }
         } catch (RemoteException e) {
         }
     }
@@ -1472,22 +1033,6 @@
             } catch (RemoteException e) { }
             mCurVibUid = -1;
         }
-        if (mIsVibrating) {
-            mIsVibrating = false;
-            notifyStateListenersLocked();
-        }
-    }
-
-    private void setVibratorUnderExternalControl(boolean externalControl) {
-        if (DEBUG) {
-            if (externalControl) {
-                Slog.d(TAG, "Vibrator going under external control.");
-            } else {
-                Slog.d(TAG, "Taking back control of vibrator.");
-            }
-        }
-        mVibratorUnderExternalControl = externalControl;
-        mNativeWrapper.vibratorSetExternalControl(externalControl);
     }
 
     private void dumpInternal(PrintWriter pw) {
@@ -1495,48 +1040,43 @@
         synchronized (mLock) {
             pw.print("  mCurrentVibration=");
             if (mCurrentVibration != null) {
-                pw.println(mCurrentVibration.toInfo().toString());
+                pw.println(mCurrentVibration.getDebugInfo().toString());
             } else {
                 pw.println("null");
             }
             pw.print("  mCurrentExternalVibration=");
             if (mCurrentExternalVibration != null) {
-                pw.println(mCurrentExternalVibration.toInfo().toString());
+                pw.println(mCurrentExternalVibration.getDebugInfo().toString());
             } else {
                 pw.println("null");
             }
-            pw.println("  mVibratorUnderExternalControl=" + mVibratorUnderExternalControl);
-            pw.println("  mIsVibrating=" + mIsVibrating);
-            pw.println("  mVibratorStateListeners Count="
-                    + mVibratorStateListeners.getRegisteredCallbackCount());
             pw.println("  mLowPowerMode=" + mLowPowerMode);
+            pw.println("  mVibratorController=" + mVibratorController);
             pw.println("  mVibrationSettings=" + mVibrationSettings);
-            pw.println("  mSupportedEffects=" + mSupportedEffects);
-            pw.println("  mSupportedPrimitives=" + mSupportedPrimitives);
             pw.println();
             pw.println("  Previous ring vibrations:");
-            for (VibrationInfo info : mPreviousRingVibrations) {
+            for (Vibration.DebugInfo info : mPreviousRingVibrations) {
                 pw.print("    ");
                 pw.println(info.toString());
             }
 
             pw.println("  Previous notification vibrations:");
-            for (VibrationInfo info : mPreviousNotificationVibrations) {
+            for (Vibration.DebugInfo info : mPreviousNotificationVibrations) {
                 pw.println("    " + info);
             }
 
             pw.println("  Previous alarm vibrations:");
-            for (VibrationInfo info : mPreviousAlarmVibrations) {
+            for (Vibration.DebugInfo info : mPreviousAlarmVibrations) {
                 pw.println("    " + info);
             }
 
             pw.println("  Previous vibrations:");
-            for (VibrationInfo info : mPreviousVibrations) {
+            for (Vibration.DebugInfo info : mPreviousVibrations) {
                 pw.println("    " + info);
             }
 
             pw.println("  Previous external vibrations:");
-            for (VibrationInfo info : mPreviousExternalVibrations) {
+            for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
                 pw.println("    " + info);
             }
         }
@@ -1547,16 +1087,16 @@
 
         synchronized (mLock) {
             if (mCurrentVibration != null) {
-                mCurrentVibration.toInfo().dumpProto(proto,
+                mCurrentVibration.getDebugInfo().dumpProto(proto,
                         VibratorServiceDumpProto.CURRENT_VIBRATION);
             }
             if (mCurrentExternalVibration != null) {
-                mCurrentExternalVibration.toInfo().dumpProto(proto,
+                mCurrentExternalVibration.getDebugInfo().dumpProto(proto,
                         VibratorServiceDumpProto.CURRENT_EXTERNAL_VIBRATION);
             }
-            proto.write(VibratorServiceDumpProto.IS_VIBRATING, mIsVibrating);
+            proto.write(VibratorServiceDumpProto.IS_VIBRATING, mVibratorController.isVibrating());
             proto.write(VibratorServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL,
-                    mVibratorUnderExternalControl);
+                    mVibratorController.isUnderExternalControl());
             proto.write(VibratorServiceDumpProto.LOW_POWER_MODE, mLowPowerMode);
             proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
                     mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_TOUCH));
@@ -1571,23 +1111,23 @@
             proto.write(VibratorServiceDumpProto.RING_DEFAULT_INTENSITY,
                     mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
 
-            for (VibrationInfo info : mPreviousRingVibrations) {
+            for (Vibration.DebugInfo info : mPreviousRingVibrations) {
                 info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS);
             }
 
-            for (VibrationInfo info : mPreviousNotificationVibrations) {
+            for (Vibration.DebugInfo info : mPreviousNotificationVibrations) {
                 info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS);
             }
 
-            for (VibrationInfo info : mPreviousAlarmVibrations) {
+            for (Vibration.DebugInfo info : mPreviousAlarmVibrations) {
                 info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS);
             }
 
-            for (VibrationInfo info : mPreviousVibrations) {
+            for (Vibration.DebugInfo info : mPreviousVibrations) {
                 info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_VIBRATIONS);
             }
 
-            for (VibrationInfo info : mPreviousExternalVibrations) {
+            for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
                 info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
             }
         }
@@ -1602,9 +1142,9 @@
         private boolean mForceStop;
 
         VibrateWaveformThread(Vibration vib) {
-            mWaveform = (VibrationEffect.Waveform) vib.effect;
-            mVibration = new Vibration(vib.token, /* effect= */ null, vib.attrs, vib.uid,
-                    vib.opPkg, vib.reason);
+            mWaveform = (VibrationEffect.Waveform) vib.getEffect();
+            mVibration = new Vibration(vib.token, /* id= */ 0, /* effect= */ null, vib.attrs,
+                    vib.uid, vib.opPkg, vib.reason);
             mTmpWorkSource.set(vib.uid);
             mWakeLock.setWorkSource(mTmpWorkSource);
         }
@@ -1676,14 +1216,18 @@
                                     // appropriate intervals.
                                     long onDuration = getTotalOnDuration(
                                             timings, amplitudes, index - 1, repeat);
-                                    mVibration.effect = VibrationEffect.createOneShot(
-                                            onDuration, amplitude);
+                                    mVibration.updateEffect(
+                                            VibrationEffect.createOneShot(onDuration, amplitude));
                                     doVibratorOn(mVibration);
                                     nextVibratorStopTime = now + onDuration;
                                 } else {
                                     // Vibrator is already ON, so just change its amplitude.
-                                    doVibratorSetAmplitude(amplitude);
+                                    mVibratorController.setAmplitude(amplitude);
                                 }
+                            } else {
+                                // Previous vibration should have already finished, but we make sure
+                                // the vibrator will be off for the next step when amplitude is 0.
+                                doVibratorOff();
                             }
 
                             // We wait until the time this waveform step was supposed to end,
@@ -1740,95 +1284,12 @@
         }
     }
 
-    /** Wrapper around the static-native methods of {@link VibratorService} for tests. */
-    @VisibleForTesting
-    public static class NativeWrapper {
-
-        private long mNativeServicePtr = 0;
-
-        /** Checks if vibrator exists on device. */
-        public boolean vibratorExists() {
-            return VibratorService.vibratorExists(mNativeServicePtr);
-        }
-
-        /** Initializes connection to vibrator HAL service. */
-        public void vibratorInit(OnCompleteListener listener) {
-            mNativeServicePtr = VibratorService.vibratorInit(listener);
-            long finalizerPtr = VibratorService.vibratorGetFinalizer();
-
-            if (finalizerPtr != 0) {
-                NativeAllocationRegistry registry =
-                        NativeAllocationRegistry.createMalloced(
-                                VibratorService.class.getClassLoader(), finalizerPtr);
-                registry.registerNativeAllocation(this, mNativeServicePtr);
-            }
-        }
-
-        /** Turns vibrator on for given time. */
-        public void vibratorOn(long milliseconds, long vibrationId) {
-            VibratorService.vibratorOn(mNativeServicePtr, milliseconds, vibrationId);
-        }
-
-        /** Turns vibrator off. */
-        public void vibratorOff() {
-            VibratorService.vibratorOff(mNativeServicePtr);
-        }
-
-        /** Sets the amplitude for the vibrator to run. */
-        public void vibratorSetAmplitude(int amplitude) {
-            VibratorService.vibratorSetAmplitude(mNativeServicePtr, amplitude);
-        }
-
-        /** Returns all predefined effects supported by the device vibrator. */
-        public int[] vibratorGetSupportedEffects() {
-            return VibratorService.vibratorGetSupportedEffects(mNativeServicePtr);
-        }
-
-        /** Returns all compose primitives supported by the device vibrator. */
-        public int[] vibratorGetSupportedPrimitives() {
-            return VibratorService.vibratorGetSupportedPrimitives(mNativeServicePtr);
-        }
-
-        /** Turns vibrator on to perform one of the supported effects. */
-        public long vibratorPerformEffect(long effect, long strength, long vibrationId) {
-            return VibratorService.vibratorPerformEffect(
-                    mNativeServicePtr, effect, strength, vibrationId);
-        }
-
-        /** Turns vibrator on to perform one of the supported composed effects. */
-        public void vibratorPerformComposedEffect(
-                VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
-            VibratorService.vibratorPerformComposedEffect(mNativeServicePtr, effect,
-                    vibrationId);
-        }
-
-        /** Enabled the device vibrator to be controlled by another service. */
-        public void vibratorSetExternalControl(boolean enabled) {
-            VibratorService.vibratorSetExternalControl(mNativeServicePtr, enabled);
-        }
-
-        /** Returns all capabilities of the device vibrator. */
-        public long vibratorGetCapabilities() {
-            return VibratorService.vibratorGetCapabilities(mNativeServicePtr);
-        }
-
-        /** Enable always-on vibration with given id and effect. */
-        public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
-            VibratorService.vibratorAlwaysOnEnable(mNativeServicePtr, id, effect, strength);
-        }
-
-        /** Disable always-on vibration for given id. */
-        public void vibratorAlwaysOnDisable(long id) {
-            VibratorService.vibratorAlwaysOnDisable(mNativeServicePtr, id);
-        }
-    }
-
     /** Point of injection for test dependencies */
     @VisibleForTesting
     static class Injector {
 
-        NativeWrapper getNativeWrapper() {
-            return new NativeWrapper();
+        VibratorController createVibratorController(OnVibrationCompleteListener listener) {
+            return new VibratorController(/* vibratorId= */ 0, listener);
         }
 
         Handler createHandler(Looper looper) {
@@ -1851,9 +1312,9 @@
                     // haptic feedback as part of the transition.  So we don't cancel
                     // system vibrations.
                     if (mCurrentVibration != null
-                            && !(mCurrentVibration.isHapticFeedback()
-                                && mCurrentVibration.isFromSystem())) {
-                        doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
+                            && !(isHapticFeedback(mCurrentVibration)
+                                && isFromSystem(mCurrentVibration))) {
+                        doCancelVibrateLocked(Vibration.Status.CANCELLED);
                     }
                 }
             }
@@ -1894,7 +1355,7 @@
 
         @Override
         public int onExternalVibrationStart(ExternalVibration vib) {
-            if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+            if (!mVibratorController.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
                 return IExternalVibratorService.SCALE_MUTE;
             }
             if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
@@ -1912,9 +1373,9 @@
                 vibHolder.scale = SCALE_MUTE;
                 if (mode == AppOpsManager.MODE_ERRORED) {
                     Slog.w(TAG, "Would be an error: external vibrate from uid " + vib.getUid());
-                    endVibrationLocked(vibHolder, VibrationInfo.Status.ERROR_APP_OPS);
+                    endVibrationLocked(vibHolder, Vibration.Status.ERROR_APP_OPS);
                 } else {
-                    endVibrationLocked(vibHolder, VibrationInfo.Status.IGNORED_APP_OPS);
+                    endVibrationLocked(vibHolder, Vibration.Status.IGNORED_APP_OPS);
                 }
                 return IExternalVibratorService.SCALE_MUTE;
             }
@@ -1929,10 +1390,13 @@
                 if (mCurrentExternalVibration == null) {
                     // If we're not under external control right now, then cancel any normal
                     // vibration that may be playing and ready the vibrator for external control.
-                    doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
-                    setVibratorUnderExternalControl(true);
+                    if (DEBUG) {
+                        Slog.d(TAG, "Vibrator going under external control.");
+                    }
+                    doCancelVibrateLocked(Vibration.Status.CANCELLED);
+                    mVibratorController.setExternalControl(true);
                 } else {
-                    endVibrationLocked(mCurrentExternalVibration, VibrationInfo.Status.CANCELLED);
+                    endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED);
                 }
                 // At this point we either have an externally controlled vibration playing, or
                 // no vibration playing. Since the interface defines that only one externally
@@ -1962,12 +1426,12 @@
                     if (DEBUG) {
                         Slog.e(TAG, "Stopping external vibration" + vib);
                     }
-                    doCancelExternalVibrateLocked(VibrationInfo.Status.FINISHED);
+                    doCancelExternalVibrateLocked(Vibration.Status.FINISHED);
                 }
             }
         }
 
-        private void doCancelExternalVibrateLocked(VibrationInfo.Status status) {
+        private void doCancelExternalVibrateLocked(Vibration.Status status) {
             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelExternalVibrateLocked");
             try {
                 if (mCurrentExternalVibration == null) {
@@ -1978,7 +1442,7 @@
                         mCurrentExternalDeathRecipient);
                 mCurrentExternalDeathRecipient = null;
                 mCurrentExternalVibration = null;
-                setVibratorUnderExternalControl(false);
+                mVibratorController.setExternalControl(false);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
             }
@@ -1991,7 +1455,7 @@
                         if (DEBUG) {
                             Slog.d(TAG, "External vibration finished because binder died");
                         }
-                        doCancelExternalVibrateLocked(VibrationInfo.Status.CANCELLED);
+                        doCancelExternalVibrateLocked(Vibration.Status.CANCELLED);
                     }
                 }
             }
@@ -2176,19 +1640,19 @@
             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runCapabilities");
             try (PrintWriter pw = getOutPrintWriter();) {
                 pw.println("Vibrator capabilities:");
-                if (hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+                if (mVibratorController.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
                     pw.println("  Always on effects");
                 }
-                if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+                if (mVibratorController.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
                     pw.println("  Compose effects");
                 }
-                if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+                if (mVibratorController.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
                     pw.println("  Amplitude control");
                 }
-                if (hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+                if (mVibratorController.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
                     pw.println("  External control");
                 }
-                if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
+                if (mVibratorController.hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
                     pw.println("  External amplitude control");
                 }
                 pw.println("");
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
index 1c77a7f..b379b5d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -23,25 +23,21 @@
 import android.annotation.NonNull;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.PackageUtils;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
-import com.android.server.accounts.AccountsDb.DeDatabaseHelper;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -163,7 +159,7 @@
                 }
                 try {
                     ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
-                    final XmlSerializer serializer = new FastXmlSerializer();
+                    final TypedXmlSerializer serializer = Xml.newFastSerializer();
                     serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
                     serializer.startDocument(null, true);
                     serializer.startTag(null, TAG_PERMISSIONS);
@@ -216,7 +212,7 @@
     public void restoreAccountAccessPermissions(byte[] data, int userId) {
         try {
             ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
-            XmlPullParser parser = Xml.newPullParser();
+            TypedXmlPullParser parser = Xml.newFastPullParser();
             parser.setInput(dataStream, StandardCharsets.UTF_8.name());
             PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
 
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index f59af76..d99b195 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -1947,8 +1947,7 @@
                                 + tagName);
                         return keyMap;
                     }
-                    int keystoreVersion = Integer.parseInt(
-                            parser.getAttributeValue(null, XML_ATTRIBUTE_VERSION));
+                    int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION);
                     if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) {
                         Slog.e(TAG, "Keystore version=" + keystoreVersion
                                 + " not supported (max_supported="
@@ -2068,8 +2067,7 @@
                                 + tagName);
                         return trustedNetworks;
                     }
-                    int keystoreVersion = Integer.parseInt(
-                            parser.getAttributeValue(null, XML_ATTRIBUTE_VERSION));
+                    int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION);
                     if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) {
                         Slog.e(TAG, "Keystore version=" + keystoreVersion
                                 + " not supported (max_supported="
@@ -2148,7 +2146,7 @@
                 serializer.startDocument(null, true);
 
                 serializer.startTag(null, XML_KEYSTORE_START_TAG);
-                serializer.attribute(null, XML_ATTRIBUTE_VERSION, String.valueOf(KEYSTORE_VERSION));
+                serializer.attributeInt(null, XML_ATTRIBUTE_VERSION, KEYSTORE_VERSION);
                 for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) {
                     serializer.startTag(null, XML_TAG_ADB_KEY);
                     serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 43474d5..61ccf11 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -52,6 +52,9 @@
     // Whether the caller holds START_ACTIVITIES_FROM_BACKGROUND permission
     boolean mHasBackgroundActivityStartsPermission;
 
+    // Whether the caller holds START_FOREGROUND_SERVICES_FROM_BACKGROUND permission
+    boolean mHasBackgroundForegroundServiceStartsPermission;
+
     // As given to us
     Bundle mArguments;
 
@@ -128,6 +131,8 @@
         }
         pw.print("mHasBackgroundActivityStartsPermission=");
         pw.println(mHasBackgroundActivityStartsPermission);
+        pw.print("mHasBackgroundForegroundServiceStartsPermission=");
+        pw.println(mHasBackgroundForegroundServiceStartsPermission);
         pw.print(prefix); pw.print("mArguments=");
         pw.println(mArguments);
     }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d6f7299..4165200 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -17,6 +17,8 @@
 package com.android.server.am;
 
 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
+import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
@@ -56,9 +58,11 @@
 import android.app.Service;
 import android.app.ServiceStartArgs;
 import android.app.admin.DevicePolicyEventLogger;
+import android.app.compat.CompatChanges;
 import android.appwidget.AppWidgetManagerInternal;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
 import android.content.ComponentName.WithComponentName;
 import android.content.Context;
@@ -104,7 +108,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.ServiceState;
-import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BatteryStatsImpl;
@@ -147,30 +150,40 @@
 
     public static final int FGS_FEATURE_DENIED = 0;
     public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
-    public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 2;
-    public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 3;
-    public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 4;
-    public static final int FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION = 5;
-    public static final int FGS_FEATURE_ALLOWED_BY_TOKEN = 6;
-    public static final int FGS_FEATURE_ALLOWED_BY_PERMISSION = 7;
-    public static final int FGS_FEATURE_ALLOWED_BY_WHITELIST = 8;
-    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 9;
-    public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 10;
-    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 11;
+    public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 2;
+    public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 3;
+    public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 4;
+    public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 5;
+    public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 6;
+    public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION = 7;
+    public static final int FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN = 8;
+    public static final int FGS_FEATURE_ALLOWED_BY_FGS_TOKEN = 9;
+    public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION = 10;
+    public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION = 12;
+    public static final int FGS_FEATURE_ALLOWED_BY_ALLOWLIST = 13;
+    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 14;
+    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 15;
+    public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
+    public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
 
     @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
             FGS_FEATURE_DENIED,
             FGS_FEATURE_ALLOWED_BY_UID_STATE,
+            FGS_FEATURE_ALLOWED_BY_PROC_STATE,
             FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
             FGS_FEATURE_ALLOWED_BY_FLAG,
             FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
-            FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION,
-            FGS_FEATURE_ALLOWED_BY_TOKEN,
-            FGS_FEATURE_ALLOWED_BY_PERMISSION,
-            FGS_FEATURE_ALLOWED_BY_WHITELIST,
+            FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
+            FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION,
+            FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN,
+            FGS_FEATURE_ALLOWED_BY_FGS_TOKEN,
+            FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION,
+            FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION,
+            FGS_FEATURE_ALLOWED_BY_ALLOWLIST,
             FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
-            FGS_FEATURE_ALLOWED_BY_PROC_STATE,
-            FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST
+            FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
+            FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
+            FGS_FEATURE_ALLOWED_BY_FGS_BINDING
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FgsFeatureRetCode {}
@@ -242,14 +255,12 @@
     AppWidgetManagerInternal mAppWidgetManagerInternal;
 
     // white listed packageName.
-    ArraySet<String> mWhiteListAllowWhileInUsePermissionInFgs = new ArraySet<>();
+    ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();
 
     // TODO: remove this after feature development is done
     private static final SimpleDateFormat DATE_FORMATTER =
             new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
-    private final IPlatformCompat mPlatformCompat;
-
     /**
      * The BG-launch FGS restriction feature is going to be allowed only for apps targetSdkVersion
      * is higher than R.
@@ -258,6 +269,14 @@
     @Disabled
     static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
 
+    /**
+     * If a service can not become foreground service due to BG-FGS-launch restriction or other
+     * reasons, throws an IllegalStateException.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+    static final long FGS_START_EXCEPTION_CHANGE_ID = 174041399L;
+
     final Runnable mLastAnrDumpClearer = new Runnable() {
         @Override public void run() {
             synchronized (mAm) {
@@ -456,26 +475,25 @@
                 ? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
 
         final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
-        mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
     }
 
     void systemServicesReady() {
         AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
         ast.addServiceStateListener(new ForcedStandbyListener());
         mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
-        setWhiteListAllowWhileInUsePermissionInFgs();
+        setAllowListWhileInUsePermissionInFgs();
     }
 
-    private void setWhiteListAllowWhileInUsePermissionInFgs() {
+    private void setAllowListWhileInUsePermissionInFgs() {
         final String attentionServicePackageName =
                 mAm.mContext.getPackageManager().getAttentionServicePackageName();
         if (!TextUtils.isEmpty(attentionServicePackageName)) {
-            mWhiteListAllowWhileInUsePermissionInFgs.add(attentionServicePackageName);
+            mAllowListWhileInUsePermissionInFgs.add(attentionServicePackageName);
         }
         final String systemCaptionsServicePackageName =
                 mAm.mContext.getPackageManager().getSystemCaptionsServicePackageName();
         if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
-            mWhiteListAllowWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
+            mAllowListWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
         }
     }
 
@@ -583,13 +601,27 @@
                     Slog.wtf(TAG, "Background started FGS " + r.mInfoAllowStartForeground);
                     r.mLoggedInfoAllowStartForeground = true;
                 }
-                if (r.mAllowStartForeground == FGS_FEATURE_DENIED
-                        && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
-                        || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
-                    Slog.w(TAG, "startForegroundService() not allowed due to "
+                if (r.mAllowStartForeground == FGS_FEATURE_DENIED && isBgFgsRestrictionEnabled(r)) {
+                    String msg = "startForegroundService() not allowed due to "
                             + "mAllowStartForeground false: service "
-                            + r.shortInstanceName);
+                            + r.shortInstanceName;
+                    Slog.w(TAG, msg);
                     showFgsBgRestrictedNotificationLocked(r);
+                    ApplicationInfo aInfo = null;
+                    try {
+                        aInfo = AppGlobals.getPackageManager().getApplicationInfo(
+                                callingPackage, ActivityManagerService.STOCK_PM_FLAGS,
+                                userId);
+                    } catch (android.os.RemoteException e) {
+                        // pm is in same process, this will never happen.
+                    }
+                    if (aInfo == null) {
+                        throw new SecurityException("startServiceLocked failed, "
+                                + "could not resolve client package " + callingPackage);
+                    }
+                    if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, aInfo.uid)) {
+                        throw new IllegalStateException(msg);
+                    }
                     return null;
                 }
             }
@@ -1449,7 +1481,7 @@
             }
 
             try {
-                boolean ignoreForeground = false;
+                String ignoreForeground = null;
                 final int mode = mAm.getAppOpsManager().checkOpNoThrow(
                         AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
                 switch (mode) {
@@ -1459,9 +1491,9 @@
                         break;
                     case AppOpsManager.MODE_IGNORED:
                         // Whoops, silently ignore this.
-                        Slog.w(TAG, "Service.startForeground() not allowed due to app op: service "
-                                + r.shortInstanceName);
-                        ignoreForeground = true;
+                        ignoreForeground = "Service.startForeground() not allowed due to app op: "
+                                + "service " + r.shortInstanceName;
+                        Slog.w(TAG, ignoreForeground);
                         break;
                     default:
                         throw new SecurityException("Foreground not allowed as per app op");
@@ -1469,19 +1501,18 @@
 
                 // Apps that are TOP or effectively similar may call startForeground() on
                 // their services even if they are restricted from doing that while in bg.
-                if (!ignoreForeground
+                if (ignoreForeground == null
                         && !appIsTopLocked(r.appInfo.uid)
                         && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
-                    Slog.w(TAG,
-                            "Service.startForeground() not allowed due to bg restriction: service "
-                            + r.shortInstanceName);
+                    ignoreForeground = "Service.startForeground() not allowed due to bg restriction"
+                            + ":service " + r.shortInstanceName;
+                    Slog.w(TAG, ignoreForeground);
                     // Back off of any foreground expectations around this service, since we've
                     // just turned down its fg request.
                     updateServiceForegroundLocked(r.app, false);
-                    ignoreForeground = true;
                 }
 
-                if (!ignoreForeground) {
+                if (ignoreForeground == null) {
                     if (isFgsBgStart(r.mAllowStartForeground)) {
                         if (!r.mLoggedInfoAllowStartForeground) {
                             Slog.wtf(TAG, "Background started FGS "
@@ -1489,14 +1520,13 @@
                             r.mLoggedInfoAllowStartForeground = true;
                         }
                         if (r.mAllowStartForeground == FGS_FEATURE_DENIED
-                                && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
-                                || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
-                            Slog.w(TAG, "Service.startForeground() not allowed due to "
-                                            + "mAllowStartForeground false: service "
-                                            + r.shortInstanceName);
+                                && isBgFgsRestrictionEnabled(r)) {
+                            ignoreForeground = "Service.startForeground() not allowed due to "
+                                    + "mAllowStartForeground false: service "
+                                    + r.shortInstanceName;
+                            Slog.w(TAG, ignoreForeground);
                             showFgsBgRestrictedNotificationLocked(r);
                             updateServiceForegroundLocked(r.app, true);
-                            ignoreForeground = true;
                         }
                     }
                 }
@@ -1505,7 +1535,7 @@
                 // services, so now that we've enforced the startForegroundService() contract
                 // we only do the machinery of making the service foreground when the app
                 // is not restricted.
-                if (!ignoreForeground) {
+                if (ignoreForeground == null) {
                     if (r.foregroundId != id) {
                         cancelForegroundNotificationLocked(r);
                         r.foregroundId = id;
@@ -1567,6 +1597,10 @@
                     if (DEBUG_FOREGROUND_SERVICE) {
                         Slog.d(TAG, "Suppressing startForeground() for FAS " + r);
                     }
+                    if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)
+                            && isBgFgsRestrictionEnabled(r)) {
+                        throw new IllegalStateException(ignoreForeground);
+                    }
                 }
             } finally {
                 if (stopProcStatsOp) {
@@ -2094,6 +2128,12 @@
                     "BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS");
         }
 
+        if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+            mAm.enforceCallingPermission(
+                    android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND,
+                    "BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND");
+        }
+
         final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
         final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
         final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
@@ -2239,6 +2279,11 @@
             if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
                 s.setAllowedBgActivityStartsByBinding(true);
             }
+
+            if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+                s.setAllowedBgFgsStartsByBinding(true);
+            }
+
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app, c, true);
             }
@@ -2256,7 +2301,6 @@
                     return 0;
                 }
             }
-
             setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, false);
 
             if (s.app != null) {
@@ -3647,6 +3691,9 @@
             if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
                 s.updateIsAllowedBgActivityStartsByBinding();
             }
+            if ((c.flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+                s.updateIsAllowedBgFgsStartsByBinding();
+            }
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app, c, true);
             }
@@ -4940,14 +4987,16 @@
      *  - the first arg isn't the flattened component name of an existing service:
      *    dump all services whose component contains the first arg as a substring
      */
-    protected boolean dumpService(FileDescriptor fd, PrintWriter pw, final String name,
+    protected boolean dumpService(FileDescriptor fd, PrintWriter pw, String name, int[] users,
             String[] args, int opti, boolean dumpAll) {
         final ArrayList<ServiceRecord> services = new ArrayList<>();
 
         final Predicate<ServiceRecord> filter = DumpUtils.filterRecord(name);
 
         synchronized (mAm) {
-            int[] users = mAm.mUserController.getUsers();
+            if (users == null) {
+                users = mAm.mUserController.getUsers();
+            }
 
             for (int user : users) {
                 ServiceMap smap = mServiceMap.get(user);
@@ -4992,11 +5041,13 @@
         String innerPrefix = prefix + "  ";
         synchronized (mAm) {
             pw.print(prefix); pw.print("SERVICE ");
-                    pw.print(r.shortInstanceName); pw.print(" ");
-                    pw.print(Integer.toHexString(System.identityHashCode(r)));
-                    pw.print(" pid=");
-                    if (r.app != null) pw.println(r.app.pid);
-                    else pw.println("(not running)");
+            pw.print(r.shortInstanceName); pw.print(" ");
+            pw.print(Integer.toHexString(System.identityHashCode(r)));
+            pw.print(" pid=");
+            if (r.app != null) {
+                pw.print(r.app.pid);
+                pw.print(" user="); pw.println(r.userId);
+            } else pw.println("(not running)");
             if (dumpAll) {
                 r.dump(pw, innerPrefix);
             }
@@ -5113,13 +5164,22 @@
         }
 
         if (ret == FGS_FEATURE_DENIED) {
+            for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+                final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+                if (pr.uid == callingUid) {
+                    if (pr.areBackgroundActivityStartsAllowedByToken()) {
+                        ret = FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (ret == FGS_FEATURE_DENIED) {
             if (r.app != null) {
                 ActiveInstrumentation instr = r.app.getActiveInstrumentation();
                 if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
-                    ret = FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION;
-                }
-                if (r.app.areBackgroundActivityStartsAllowedByToken()) {
-                    ret = FGS_FEATURE_ALLOWED_BY_TOKEN;
+                    ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
                 }
             }
         }
@@ -5127,15 +5187,15 @@
         if (ret == FGS_FEATURE_DENIED) {
             if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
                     == PERMISSION_GRANTED) {
-                ret = FGS_FEATURE_ALLOWED_BY_PERMISSION;
+                ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
             }
         }
 
         if (ret == FGS_FEATURE_DENIED) {
-            final boolean isWhiteListedPackage =
-                    mWhiteListAllowWhileInUsePermissionInFgs.contains(callingPackage);
-            if (isWhiteListedPackage) {
-                ret = FGS_FEATURE_ALLOWED_BY_WHITELIST;
+            final boolean isAllowedPackage =
+                    mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
+            if (isAllowedPackage) {
+                ret = FGS_FEATURE_ALLOWED_BY_ALLOWLIST;
             }
         }
 
@@ -5187,6 +5247,39 @@
         }
 
         if (ret == FGS_FEATURE_DENIED) {
+            for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+                final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+                if (pr.uid == callingUid) {
+                    if (pr.areBackgroundFgsStartsAllowedByToken()) {
+                        ret = FGS_FEATURE_ALLOWED_BY_FGS_BINDING;
+                        break;
+                    } else {
+                        final ActiveInstrumentation instr = pr.getActiveInstrumentation();
+                        if (instr != null
+                                && instr.mHasBackgroundForegroundServiceStartsPermission) {
+                            ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (ret == FGS_FEATURE_DENIED) {
+            if (mAm.checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid,
+                    callingUid) == PERMISSION_GRANTED) {
+                ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
+            }
+        }
+
+        if (ret == FGS_FEATURE_DENIED) {
+            if (mAm.checkPermission(SYSTEM_ALERT_WINDOW, callingPid,
+                    callingUid) == PERMISSION_GRANTED) {
+                ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
+            }
+        }
+
+        if (ret == FGS_FEATURE_DENIED) {
             if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
                     && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
                 // uid is on DeviceIdleController's allowlist.
@@ -5217,26 +5310,36 @@
                 return "DENIED";
             case FGS_FEATURE_ALLOWED_BY_UID_STATE:
                 return "ALLOWED_BY_UID_STATE";
+            case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
+                return "ALLOWED_BY_PROC_STATE";
             case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
                 return "ALLOWED_BY_UID_VISIBLE";
             case FGS_FEATURE_ALLOWED_BY_FLAG:
                 return "ALLOWED_BY_FLAG";
             case FGS_FEATURE_ALLOWED_BY_SYSTEM_UID:
                 return "ALLOWED_BY_SYSTEM_UID";
-            case FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION:
-                return "ALLOWED_BY_INSTR_PERMISSION";
-            case FGS_FEATURE_ALLOWED_BY_TOKEN:
-                return "ALLOWED_BY_TOKEN";
-            case FGS_FEATURE_ALLOWED_BY_PERMISSION:
-                return "ALLOWED_BY_PERMISSION";
-            case FGS_FEATURE_ALLOWED_BY_WHITELIST:
+            case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
+                return "ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION";
+            case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION:
+                return "ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION";
+            case FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN:
+                return "ALLOWED_BY_ACTIVITY_TOKEN";
+            case FGS_FEATURE_ALLOWED_BY_FGS_TOKEN:
+                return "ALLOWED_BY_FGS_TOKEN";
+            case FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION:
+                return "ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION";
+            case FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION:
+                return "ALLOWED_BY_BACKGROUND_FGS_PERMISSION";
+            case FGS_FEATURE_ALLOWED_BY_ALLOWLIST:
                 return "ALLOWED_BY_WHITELIST";
             case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
                 return "ALLOWED_BY_DEVICE_OWNER";
-            case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
-                return "ALLOWED_BY_PROC_STATE";
             case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
                 return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
+            case FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION:
+                return "ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION";
+            case FGS_FEATURE_ALLOWED_BY_FGS_BINDING:
+                return "ALLOWED_BY_FGS_BINDING";
             default:
                 return "";
         }
@@ -5271,11 +5374,10 @@
                 NOTE_FOREGROUND_SERVICE_BG_LAUNCH, n.build(), UserHandle.ALL);
     }
 
-    private boolean isChangeEnabled(long changeId, ServiceRecord r) {
-        boolean enabled = false;
-        try {
-            enabled = mPlatformCompat.isChangeEnabled(changeId, r.appInfo);
-        } catch (RemoteException e) { }
-        return enabled;
+    private boolean isBgFgsRestrictionEnabled(ServiceRecord r) {
+        if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
+            return true;
+        }
+        return CompatChanges.isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r.appInfo.uid);
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9eca15b..df1081e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
@@ -5643,7 +5644,7 @@
 
     @Override
     public List<RunningTaskInfo> getTasks(int maxNum) {
-        return mActivityTaskManager.getTasks(maxNum);
+        return mActivityTaskManager.getTasks(maxNum, false /* filterForVisibleRecents */);
     }
 
     @Override
@@ -8663,17 +8664,30 @@
             } else if ("service".equals(cmd)) {
                 String[] newArgs;
                 String name;
+                int[] users = null;
                 if (opti >= args.length) {
                     name = null;
                     newArgs = EMPTY_STRING_ARRAY;
                 } else {
                     name = args[opti];
                     opti++;
+                    if ("--user".equals(name) && opti < args.length) {
+                        int userId = UserHandle.parseUserArg(args[opti]);
+                        opti++;
+                        if (userId != UserHandle.USER_ALL) {
+                            if (userId == UserHandle.USER_CURRENT) {
+                                userId = getCurrentUser().id;
+                            }
+                            users = new int[] { userId };
+                        }
+                        name = args[opti];
+                        opti++;
+                    }
                     newArgs = new String[args.length - opti];
                     if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
                             args.length - opti);
                 }
-                if (!mServices.dumpService(fd, pw, name, newArgs, 0, dumpAll)) {
+                if (!mServices.dumpService(fd, pw, name, users, newArgs, 0, dumpAll)) {
                     pw.println("No services match: " + name);
                     pw.println("Use -h for help.");
                 }
@@ -13321,15 +13335,22 @@
                 // See if the caller is allowed to do this.  Note we are checking against
                 // the actual real caller (not whoever provided the operation as say a
                 // PendingIntent), because that who is actually supplied the arguments.
-                if (checkComponentPermission(
-                        android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+                if (checkComponentPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+                        realCallingPid, realCallingUid, -1, true)
+                        != PackageManager.PERMISSION_GRANTED
+                        && checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
+                        realCallingPid, realCallingUid, -1, true)
+                        != PackageManager.PERMISSION_GRANTED
+                        && checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND,
                         realCallingPid, realCallingUid, -1, true)
                         != PackageManager.PERMISSION_GRANTED) {
                     String msg = "Permission Denial: " + intent.getAction()
                             + " broadcast from " + callerPackage + " (pid=" + callingPid
                             + ", uid=" + callingUid + ")"
                             + " requires "
-                            + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
+                            + CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or "
+                            + START_ACTIVITIES_FROM_BACKGROUND + " or "
+                            + START_FOREGROUND_SERVICES_FROM_BACKGROUND;
                     Slog.w(TAG, msg);
                     throw new SecurityException(msg);
                 }
@@ -14289,8 +14310,10 @@
             activeInstr.mHasBackgroundActivityStartsPermission = checkPermission(
                     START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
                             == PackageManager.PERMISSION_GRANTED;
+            activeInstr.mHasBackgroundForegroundServiceStartsPermission = checkPermission(
+                    START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
+                            == PackageManager.PERMISSION_GRANTED;
             activeInstr.mNoRestart = noRestart;
-
             boolean disableHiddenApiChecks = ai.usesNonSdkApi()
                     || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
             boolean disableTestApiChecks = disableHiddenApiChecks
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 93dd1aa..fdc0f59 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -37,13 +37,14 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.power.MeasuredEnergyArray;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.function.pooled.PooledLambda;
 
-import java.util.concurrent.ExecutionException;
 import libcore.util.EmptyArray;
 
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -103,6 +104,9 @@
     private boolean mOnBatteryScreenOff;
 
     @GuardedBy("this")
+    private int mScreenState;
+
+    @GuardedBy("this")
     private boolean mUseLatestStates = true;
 
     @GuardedBy("this")
@@ -194,15 +198,17 @@
     }
 
     @Override
-    public Future<?> scheduleCpuSyncDueToScreenStateChange(
-            boolean onBattery, boolean onBatteryScreenOff) {
+    public Future<?> scheduleSyncDueToScreenStateChange(
+            int flags, boolean onBattery, boolean onBatteryScreenOff, int screenState) {
         synchronized (BatteryExternalStatsWorker.this) {
             if (mCurrentFuture == null || (mUpdateFlags & UPDATE_CPU) == 0) {
                 mOnBattery = onBattery;
                 mOnBatteryScreenOff = onBatteryScreenOff;
                 mUseLatestStates = false;
             }
-            return scheduleSyncLocked("screen-state", UPDATE_CPU);
+            // always update screen state
+            mScreenState = screenState;
+            return scheduleSyncLocked("screen-state", flags);
         }
     }
 
@@ -332,6 +338,7 @@
             final int[] uidsToRemove;
             final boolean onBattery;
             final boolean onBatteryScreenOff;
+            final int screenState;
             final boolean useLatestStates;
             synchronized (BatteryExternalStatsWorker.this) {
                 updateFlags = mUpdateFlags;
@@ -339,6 +346,7 @@
                 uidsToRemove = mUidsToRemove.size() > 0 ? mUidsToRemove.toArray() : EmptyArray.INT;
                 onBattery = mOnBattery;
                 onBatteryScreenOff = mOnBatteryScreenOff;
+                screenState = mScreenState;
                 useLatestStates = mUseLatestStates;
                 mUpdateFlags = 0;
                 mCurrentReason = null;
@@ -360,7 +368,7 @@
                     }
                     try {
                         updateExternalStatsLocked(reason, updateFlags, onBattery,
-                                onBatteryScreenOff, useLatestStates);
+                                onBatteryScreenOff, screenState, useLatestStates);
                     } finally {
                         if (DEBUG) {
                             Slog.d(TAG, "end updateExternalStatsSync");
@@ -402,13 +410,14 @@
     };
 
     @GuardedBy("mWorkerLock")
-    private void updateExternalStatsLocked(final String reason, int updateFlags,
-            boolean onBattery, boolean onBatteryScreenOff, boolean useLatestStates) {
+    private void updateExternalStatsLocked(final String reason, int updateFlags, boolean onBattery,
+            boolean onBatteryScreenOff, int screenState, boolean useLatestStates) {
         // We will request data from external processes asynchronously, and wait on a timeout.
         SynchronousResultReceiver wifiReceiver = null;
         SynchronousResultReceiver bluetoothReceiver = null;
         CompletableFuture<ModemActivityInfo> modemFuture = CompletableFuture.completedFuture(null);
         boolean railUpdated = false;
+        MeasuredEnergyArray energyArray = null;
 
         if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
             // We were asked to fetch WiFi data.
@@ -486,6 +495,13 @@
             }
         }
 
+        if ((updateFlags & UPDATE_ENERGY) != 0) {
+            synchronized (mStats) {
+                // TODO(b/172934873) evaluate a safe way to query the HAL without holding mStats
+                energyArray = mStats.getEnergyConsumptionDataLocked();
+            }
+        }
+
         final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
         final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
         ModemActivityInfo modemInfo = null;
@@ -533,6 +549,11 @@
                     Slog.w(TAG, "bluetooth info is invalid: " + bluetoothInfo);
                 }
             }
+
+            if ((updateFlags & UPDATE_ENERGY) != 0 && energyArray != null) {
+                // Always use what BatteryExternalStatsWorker thinks screenState is.
+                mStats.updateMeasuredEnergyStatsLocked(energyArray, screenState);
+            }
         }
 
         // WiFi and Modem state are updated without the mStats lock held, because they
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ed2faf9..46e16bc 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,6 +21,8 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.hardware.power.stats.EnergyConsumerId;
+import android.hardware.power.stats.EnergyConsumerResult;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
@@ -59,6 +61,7 @@
 import com.android.internal.os.PowerProfile;
 import com.android.internal.os.RailStats;
 import com.android.internal.os.RpmStats;
+import com.android.internal.power.MeasuredEnergyArray;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ParseUtils;
@@ -66,6 +69,7 @@
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import com.android.server.pm.UserManagerInternal;
+import com.android.server.powerstats.PowerStatsHALWrapper;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -90,7 +94,7 @@
 public final class BatteryStatsService extends IBatteryStats.Stub
         implements PowerManagerInternal.LowPowerModeListener,
         BatteryStatsImpl.PlatformIdleStateCallback,
-        BatteryStatsImpl.RailEnergyDataCallback,
+        BatteryStatsImpl.MeasuredEnergyRetriever,
         Watchdog.Monitor {
     static final String TAG = "BatteryStatsService";
     static final boolean DBG = false;
@@ -115,6 +119,8 @@
     private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
     private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
 
+    private final PowerStatsHALWrapper.IPowerStatsHALWrapper mPowerStatsHALWrapper;
+
     private final HandlerThread mHandlerThread;
     private final Handler mHandler;
     private final Object mLock = new Object();
@@ -186,6 +192,43 @@
         }
     }
 
+    @Override
+    public MeasuredEnergyArray getEnergyConsumptionData() {
+        final EnergyConsumerResult[] results = mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
+        if (results == null) return null;
+        final int size = results.length;
+        final int[] subsystems = new int[size];
+        final long[] energyUJ = new long[size];
+
+        for (int i = 0; i < size; i++) {
+            final EnergyConsumerResult consumer = results[i];
+            final int subsystem;
+            switch (consumer.energyConsumerId) {
+                case EnergyConsumerId.DISPLAY:
+                    subsystem = MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
+                    break;
+                default:
+                    continue;
+            }
+            subsystems[i] = subsystem;
+            energyUJ[i] = consumer.energyUWs;
+        }
+        return new MeasuredEnergyArray() {
+            @Override
+            public int getSubsystem(int index) {
+                return subsystems[index];
+            }
+            @Override
+            public long getEnergy(int index) {
+                return energyUJ[index];
+            }
+            @Override
+            public int size() {
+                return size;
+            }
+        };
+    }
+
     BatteryStatsService(Context context, File systemDir, Handler handler) {
         // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
         mContext = context;
@@ -202,6 +245,12 @@
         mHandlerThread = new HandlerThread("batterystats-handler");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
+
+        // TODO(b/173077356): Replace directly calling the HAL with PowerStatsService queries
+        // Make sure to init Hal Wrapper before creating BatteryStatsImpl.
+        mPowerStatsHALWrapper = new PowerStatsHALWrapper.PowerStatsHALWrapperImpl();
+        mPowerStatsHALWrapper.initialize();
+
         mStats = new BatteryStatsImpl(systemDir, handler, this,
                 this, mUserManagerUserInfoProvider);
         mWorker = new BatteryExternalStatsWorker(context, mStats);
@@ -1963,6 +2012,15 @@
         }
     }
 
+    private void dumpMeasuredEnergyStats(PrintWriter pw) {
+        // Wait for the completion of pending works if there is any
+        awaitCompletion();
+        syncStats("dump", BatteryExternalStatsWorker.UPDATE_ENERGY);
+        synchronized (mStats) {
+            mStats.dumpMeasuredEnergyStatsLocked(pw);
+        }
+    }
+
     private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
         i++;
         if (i >= args.length) {
@@ -2103,6 +2161,9 @@
                 } else if ("--cpu".equals(arg)) {
                     dumpCpuStats(pw);
                     return;
+                } else  if ("--measured-energy".equals(arg)) {
+                    dumpMeasuredEnergyStats(pw);
+                    return;
                 } else if ("-a".equals(arg)) {
                     flags |= BatteryStats.DUMP_VERBOSE;
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 1b06dd9..cf4adc6 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -359,6 +359,8 @@
     // It must obtain the proc state from a persistent/top process or FGS, not transitive.
     int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
 
+    private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
+
     void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
             long startTime) {
         this.startUid = startUid;
@@ -1965,6 +1967,18 @@
         }
     }
 
+    public void addAllowBackgroundFgsStartsToken(Binder entity) {
+        mBackgroundFgsStartTokens.add(entity);
+    }
+
+    public void removeAllowBackgroundFgsStartsToken(Binder entity) {
+        mBackgroundFgsStartTokens.remove(entity);
+    }
+
+    public boolean areBackgroundFgsStartsAllowedByToken() {
+        return !mBackgroundFgsStartTokens.isEmpty();
+    }
+
     ErrorDialogController getDialogController() {
         return mDialogController;
     }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 364ad21..e129561 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -147,6 +147,10 @@
     @GuardedBy("ams")
     private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>();
 
+    // any current binding to this service has BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND
+    // flag? if true, the process can start FGS from background.
+    boolean mIsAllowedBgFgsStartsByBinding;
+
     // allow while-in-use permissions in foreground service or not.
     // while-in-use permissions in FGS started from background might be restricted.
     boolean mAllowWhileInUsePermissionInFgs;
@@ -418,6 +422,10 @@
             pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart=");
             pw.println(mIsAllowedBgActivityStartsByStart);
         }
+        if (mIsAllowedBgFgsStartsByBinding) {
+            pw.print(prefix); pw.print("mIsAllowedBgFgsStartsByBinding=");
+            pw.println(mIsAllowedBgFgsStartsByBinding);
+        }
         pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
                 pw.println(mAllowWhileInUsePermissionInFgs);
         pw.print(prefix); pw.print("recentCallingPackage=");
@@ -600,6 +608,11 @@
             } else {
                 _proc.removeAllowBackgroundActivityStartsToken(this);
             }
+            if (mIsAllowedBgFgsStartsByBinding) {
+                _proc.addAllowBackgroundFgsStartsToken(this);
+            } else {
+                _proc.removeAllowBackgroundFgsStartsToken(this);
+            }
         }
         if (app != null && app != _proc) {
             // If the old app is allowed to start bg activities because of a service start, leave it
@@ -686,11 +699,34 @@
         setAllowedBgActivityStartsByBinding(isAllowedByBinding);
     }
 
+    void updateIsAllowedBgFgsStartsByBinding() {
+        boolean isAllowedByBinding = false;
+        for (int conni = connections.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
+            for (int i = 0; i < cr.size(); i++) {
+                if ((cr.get(i).flags
+                        & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+                    isAllowedByBinding = true;
+                    break;
+                }
+            }
+            if (isAllowedByBinding) {
+                break;
+            }
+        }
+        setAllowedBgFgsStartsByBinding(isAllowedByBinding);
+    }
+
     void setAllowedBgActivityStartsByBinding(boolean newValue) {
         mIsAllowedBgActivityStartsByBinding = newValue;
         updateParentProcessBgActivityStartsToken();
     }
 
+    void setAllowedBgFgsStartsByBinding(boolean newValue) {
+        mIsAllowedBgFgsStartsByBinding = newValue;
+        updateParentProcessBgFgsStartsToken();
+    }
+
     /**
      * Called when the service is started with allowBackgroundActivityStarts set. We allow
      * it for background activity starts, setting up a callback to remove this ability after a
@@ -777,6 +813,17 @@
         }
     }
 
+    private void updateParentProcessBgFgsStartsToken() {
+        if (app == null) {
+            return;
+        }
+        if (mIsAllowedBgFgsStartsByBinding) {
+            app.addAllowBackgroundFgsStartsToken(this);
+        } else {
+            app.removeAllowBackgroundFgsStartsToken(this);
+        }
+    }
+
     /**
      * Returns the originating token if that's the only reason background activity starts are
      * allowed. In order for that to happen the service has to be allowed only due to starts, since
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 28afcbb..7299e81 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -88,6 +88,8 @@
         DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
         DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+        DeviceConfig.NAMESPACE_STATSD_NATIVE,
+        DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
     };
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index da47040..d4e2d27 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -124,7 +124,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
 import android.provider.Settings;
 import android.util.ArrayMap;
@@ -155,10 +154,8 @@
 import com.android.internal.app.IAppOpsStartedCallback;
 import com.android.internal.app.MessageSamplingConfig;
 import com.android.internal.compat.IPlatformCompat;
-import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -175,7 +172,6 @@
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -185,7 +181,6 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
@@ -1057,19 +1052,20 @@
             }
 
             int numInProgressEvents = mInProgressEvents.size();
+            List<IBinder> binders = new ArrayList<>(mInProgressEvents.keySet());
             for (int i = 0; i < numInProgressEvents; i++) {
-                InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
+                InProgressStartOpEvent event = mInProgressEvents.get(binders.get(i));
 
-                if (event.getUidState() != newState) {
+                if (event != null && event.getUidState() != newState) {
                     try {
                         // Remove all but one unfinished start count and then call finished() to
                         // remove start event object
                         int numPreviousUnfinishedStarts = event.numUnfinishedStarts;
                         event.numUnfinishedStarts = 1;
-                        finished(event.getClientId(), false);
-
                         OpEventProxyInfo proxy = event.getProxy();
 
+                        finished(event.getClientId(), false);
+
                         // Call started() to add a new start event object and then add the
                         // previously removed unfinished start counts back
                         if (proxy != null) {
@@ -1079,7 +1075,11 @@
                             started(event.getClientId(), Process.INVALID_UID, null, null, newState,
                                     OP_FLAG_SELF, false);
                         }
-                        event.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
+
+                        InProgressStartOpEvent newEvent = mInProgressEvents.get(binders.get(i));
+                        if (newEvent != null) {
+                            newEvent.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
+                        }
                     } catch (RemoteException e) {
                         if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
                     }
@@ -1764,26 +1764,6 @@
                     }
                 });
 
-        if (!StorageManager.hasIsolatedStorage()) {
-            StorageManagerInternal storageManagerInternal = LocalServices.getService(
-                    StorageManagerInternal.class);
-            storageManagerInternal.addExternalStoragePolicy(
-                    new StorageManagerInternal.ExternalStorageMountPolicy() {
-                        @Override
-                        public int getMountMode(int uid, String packageName) {
-                            if (Process.isIsolated(uid)) {
-                                return Zygote.MOUNT_EXTERNAL_NONE;
-                            }
-                            return Zygote.MOUNT_EXTERNAL_DEFAULT;
-                        }
-
-                        @Override
-                        public boolean hasExternalStorage(int uid, String packageName) {
-                            final int mountMode = getMountMode(uid, packageName);
-                            return mountMode != Zygote.MOUNT_EXTERNAL_NONE;
-                        }
-                    });
-        }
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
     }
 
@@ -4285,10 +4265,7 @@
                         throw new IllegalStateException("no start tag found");
                     }
 
-                    final String versionString = parser.getAttributeValue(null, "v");
-                    if (versionString != null) {
-                        oldVersion = Integer.parseInt(versionString);
-                    }
+                    oldVersion = parser.getAttributeInt(null, "v", NO_VERSION);
 
                     int outerDepth = parser.getDepth();
                     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4388,9 +4365,9 @@
         scheduleFastWriteLocked();
     }
 
-    private void readUidOps(XmlPullParser parser) throws NumberFormatException,
+    private void readUidOps(TypedXmlPullParser parser) throws NumberFormatException,
             XmlPullParserException, IOException {
-        final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+        final int uid = parser.getAttributeInt(null, "n");
         int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4401,8 +4378,8 @@
 
             String tagName = parser.getName();
             if (tagName.equals("op")) {
-                final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
-                final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
+                final int code = parser.getAttributeInt(null, "n");
+                final int mode = parser.getAttributeInt(null, "m");
                 setUidMode(code, uid, mode);
             } else {
                 Slog.w(TAG, "Unknown element under <uid-ops>: "
@@ -4412,7 +4389,7 @@
         }
     }
 
-    private void readPackage(XmlPullParser parser)
+    private void readPackage(TypedXmlPullParser parser)
             throws NumberFormatException, XmlPullParserException, IOException {
         String pkgName = parser.getAttributeValue(null, "n");
         int outerDepth = parser.getDepth();
@@ -4434,9 +4411,9 @@
         }
     }
 
-    private void readUid(XmlPullParser parser, String pkgName)
+    private void readUid(TypedXmlPullParser parser, String pkgName)
             throws NumberFormatException, XmlPullParserException, IOException {
-        int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+        int uid = parser.getAttributeInt(null, "n");
         final UidState uidState = getUidStateLocked(uid, true);
         int outerDepth = parser.getDepth();
         int type;
@@ -4457,19 +4434,20 @@
         uidState.evalForegroundOps(mOpModeWatchers);
     }
 
-    private void readAttributionOp(XmlPullParser parser, @NonNull Op parent,
-            @Nullable String attribution) throws NumberFormatException, IOException {
+    private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
+            @Nullable String attribution)
+            throws NumberFormatException, IOException, XmlPullParserException {
         final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
 
-        final long key = XmlUtils.readLongAttribute(parser, "n");
+        final long key = parser.getAttributeLong(null, "n");
         final int uidState = extractUidStateFromKey(key);
         final int opFlags = extractFlagsFromKey(key);
 
-        final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
-        final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
-        final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1);
+        final long accessTime = parser.getAttributeLong(null, "t", 0);
+        final long rejectTime = parser.getAttributeLong(null, "r", 0);
+        final long accessDuration = parser.getAttributeLong(null, "d", -1);
         final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
-        final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID);
+        final int proxyUid = parser.getAttributeInt(null, "pu", Process.INVALID_UID);
         final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
 
         if (accessTime > 0) {
@@ -4481,14 +4459,13 @@
         }
     }
 
-    private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)
-            throws NumberFormatException,
-        XmlPullParserException, IOException {
-        int opCode = Integer.parseInt(parser.getAttributeValue(null, "n"));
+    private void readOp(TypedXmlPullParser parser,
+            @NonNull UidState uidState, @NonNull String pkgName)
+            throws NumberFormatException, XmlPullParserException, IOException {
+        int opCode = parser.getAttributeInt(null, "n");
         Op op = new Op(uidState, pkgName, opCode, uidState.uid);
 
-        final int mode = XmlUtils.readIntAttribute(parser, "m",
-                AppOpsManager.opToDefaultMode(op.op));
+        final int mode = parser.getAttributeInt(null, "m", AppOpsManager.opToDefaultMode(op.op));
         op.mode = mode;
 
         int outerDepth = parser.getDepth();
@@ -4535,7 +4512,7 @@
                 TypedXmlSerializer out = Xml.resolveSerializer(stream);
                 out.startDocument(null, true);
                 out.startTag(null, "app-ops");
-                out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
+                out.attributeInt(null, "v", CURRENT_VERSION);
 
                 SparseArray<SparseIntArray> uidStatesClone;
                 synchronized (this) {
@@ -4565,15 +4542,14 @@
                     SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
                     if (opModes != null && opModes.size() > 0) {
                         out.startTag(null, "uid");
-                        out.attribute(null, "n",
-                                Integer.toString(uidStatesClone.keyAt(uidStateNum)));
+                        out.attributeInt(null, "n", uidStatesClone.keyAt(uidStateNum));
                         final int opCount = opModes.size();
                         for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
                             final int op = opModes.keyAt(opCountNum);
                             final int mode = opModes.valueAt(opCountNum);
                             out.startTag(null, "op");
-                            out.attribute(null, "n", Integer.toString(op));
-                            out.attribute(null, "m", Integer.toString(mode));
+                            out.attributeInt(null, "n", op);
+                            out.attributeInt(null, "m", mode);
                             out.endTag(null, "op");
                         }
                         out.endTag(null, "uid");
@@ -4593,14 +4569,14 @@
                             out.attribute(null, "n", lastPkg);
                         }
                         out.startTag(null, "uid");
-                        out.attribute(null, "n", Integer.toString(pkg.getUid()));
+                        out.attributeInt(null, "n", pkg.getUid());
                         List<AppOpsManager.OpEntry> ops = pkg.getOps();
                         for (int j=0; j<ops.size(); j++) {
                             AppOpsManager.OpEntry op = ops.get(j);
                             out.startTag(null, "op");
-                            out.attribute(null, "n", Integer.toString(op.getOp()));
+                            out.attributeInt(null, "n", op.getOp());
                             if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
-                                out.attribute(null, "m", Integer.toString(op.getMode()));
+                                out.attributeInt(null, "m", op.getMode());
                             }
 
                             for (String attributionTag : op.getAttributedOpEntries().keySet()) {
@@ -4644,15 +4620,15 @@
                                     if (attributionTag != null) {
                                         out.attribute(null, "id", attributionTag);
                                     }
-                                    out.attribute(null, "n", Long.toString(key));
+                                    out.attributeLong(null, "n", key);
                                     if (accessTime > 0) {
-                                        out.attribute(null, "t", Long.toString(accessTime));
+                                        out.attributeLong(null, "t", accessTime);
                                     }
                                     if (rejectTime > 0) {
-                                        out.attribute(null, "r", Long.toString(rejectTime));
+                                        out.attributeLong(null, "r", rejectTime);
                                     }
                                     if (accessDuration > 0) {
-                                        out.attribute(null, "d", Long.toString(accessDuration));
+                                        out.attributeLong(null, "d", accessDuration);
                                     }
                                     if (proxyPkg != null) {
                                         out.attribute(null, "pp", proxyPkg);
@@ -4661,7 +4637,7 @@
                                         out.attribute(null, "pc", proxyAttributionTag);
                                     }
                                     if (proxyUid >= 0) {
-                                        out.attribute(null, "pu", Integer.toString(proxyUid));
+                                        out.attributeInt(null, "pu", proxyUid);
                                     }
                                     out.endTag(null, "st");
                                 }
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index f49b5dc..676fcd0 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -49,6 +49,8 @@
 import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -1184,19 +1186,18 @@
             }
             List<HistoricalOps> allOps = null;
             try (FileInputStream stream = new FileInputStream(file)) {
-                final XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(stream, StandardCharsets.UTF_8.name());
+                final TypedXmlPullParser parser = Xml.resolvePullParser(stream);
                 XmlUtils.beginDocument(parser, TAG_HISTORY);
 
                 // We haven't released version 1 and have more detailed
                 // accounting - just nuke the current state
-                final int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION);
+                final int version = parser.getAttributeInt(null, ATTR_VERSION);
                 if (CURRENT_VERSION == 2 && version < CURRENT_VERSION) {
                     throw new IllegalStateException("Dropping unsupported history "
                             + "version 1 for file:" + file);
                 }
 
-                final long overflowMillis = XmlUtils.readLongAttribute(parser, ATTR_OVERFLOW, 0);
+                final long overflowMillis = parser.getAttributeLong(null, ATTR_OVERFLOW, 0);
                 final int depth = parser.getDepth();
                 while (XmlUtils.nextElementWithin(parser, depth)) {
                     if (TAG_OPS.equals(parser.getName())) {
@@ -1235,15 +1236,16 @@
         }
 
         private @Nullable HistoricalOps readeHistoricalOpsDLocked(
-                @NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
+                @NonNull TypedXmlPullParser parser, int filterUid,
+                @Nullable String filterPackageName,
                 @Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
                 @HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
                 long filterEndTimeMillis, @OpFlags int filterFlags,
                 @Nullable long[] cumulativeOverflowMillis)
                 throws IOException, XmlPullParserException {
-            final long beginTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_BEGIN_TIME, 0)
+            final long beginTimeMillis = parser.getAttributeLong(null, ATTR_BEGIN_TIME, 0)
                     + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
-            final long endTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_END_TIME, 0)
+            final long endTimeMillis = parser.getAttributeLong(null, ATTR_END_TIME, 0)
                     + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
             // Keep reading as subsequent records may start matching
             if (filterEndTimeMillis < beginTimeMillis) {
@@ -1280,12 +1282,12 @@
         }
 
         private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
-                @Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
+                @Nullable HistoricalOps ops, @NonNull TypedXmlPullParser parser, int filterUid,
                 @Nullable String filterPackageName, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 @OpFlags int filterFlags, double filterScale)
                 throws IOException, XmlPullParserException {
-            final int uid = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            final int uid = parser.getAttributeInt(null, ATTR_NAME);
             if ((filter & FILTER_BY_UID) != 0 && filterUid != uid) {
                 XmlUtils.skipCurrentTag(parser);
                 return null;
@@ -1305,7 +1307,7 @@
         }
 
         private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
-                @Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
+                @Nullable HistoricalOps ops, int uid, @NonNull TypedXmlPullParser parser,
                 @Nullable String filterPackageName, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 @OpFlags int filterFlags, double filterScale)
@@ -1331,7 +1333,7 @@
 
         private @Nullable HistoricalOps readHistoricalAttributionOpsDLocked(
                 @Nullable HistoricalOps ops, int uid, String packageName,
-                @NonNull XmlPullParser parser, @Nullable String filterAttributionTag,
+                @NonNull TypedXmlPullParser parser, @Nullable String filterAttributionTag,
                 @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
                 @OpFlags int filterFlags, double filterScale)
                 throws IOException, XmlPullParserException {
@@ -1357,11 +1359,11 @@
 
         private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
                 int uid, @NonNull String packageName, @Nullable String attributionTag,
-                @NonNull XmlPullParser parser, @Nullable String[] filterOpNames,
+                @NonNull TypedXmlPullParser parser, @Nullable String[] filterOpNames,
                 @HistoricalOpsRequestFilter int filter, @OpFlags int filterFlags,
                 double filterScale)
                 throws IOException, XmlPullParserException {
-            final int op = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            final int op = parser.getAttributeInt(null, ATTR_NAME);
             if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(filterOpNames,
                     AppOpsManager.opToPublicName(op))) {
                 XmlUtils.skipCurrentTag(parser);
@@ -1382,15 +1384,15 @@
 
         private @Nullable HistoricalOps readStateDLocked(@Nullable HistoricalOps ops,
                 int uid, @NonNull String packageName, @Nullable String attributionTag, int op,
-                @NonNull XmlPullParser parser, @OpFlags int filterFlags, double filterScale)
-                throws IOException {
-            final long key = XmlUtils.readLongAttribute(parser, ATTR_NAME);
+                @NonNull TypedXmlPullParser parser, @OpFlags int filterFlags, double filterScale)
+                throws IOException, XmlPullParserException {
+            final long key = parser.getAttributeLong(null, ATTR_NAME);
             final int flags = AppOpsManager.extractFlagsFromKey(key) & filterFlags;
             if (flags == 0) {
                 return null;
             }
             final int uidState = AppOpsManager.extractUidStateFromKey(key);
-            long accessCount = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_COUNT, 0);
+            long accessCount = parser.getAttributeLong(null, ATTR_ACCESS_COUNT, 0);
             if (accessCount > 0) {
                 if (!Double.isNaN(filterScale)) {
                     accessCount = (long) HistoricalOps.round(
@@ -1402,7 +1404,7 @@
                 ops.increaseAccessCount(op, uid, packageName, attributionTag, uidState, flags,
                         accessCount);
             }
-            long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
+            long rejectCount = parser.getAttributeLong(null, ATTR_REJECT_COUNT, 0);
             if (rejectCount > 0) {
                 if (!Double.isNaN(filterScale)) {
                     rejectCount = (long) HistoricalOps.round(
@@ -1414,7 +1416,7 @@
                 ops.increaseRejectCount(op, uid, packageName, attributionTag, uidState, flags,
                         rejectCount);
             }
-            long accessDuration =  XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
+            long accessDuration =  parser.getAttributeLong(null, ATTR_ACCESS_DURATION, 0);
             if (accessDuration > 0) {
                 if (!Double.isNaN(filterScale)) {
                     accessDuration = (long) HistoricalOps.round(
@@ -1433,16 +1435,14 @@
                 long intervalOverflowMillis, @NonNull File file) throws IOException {
             final FileOutputStream output = sHistoricalAppOpsDir.openWrite(file);
             try {
-                final XmlSerializer serializer = Xml.newSerializer();
-                serializer.setOutput(output, StandardCharsets.UTF_8.name());
+                final TypedXmlSerializer serializer = Xml.resolveSerializer(output);
                 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
                         true);
                 serializer.startDocument(null, true);
                 serializer.startTag(null, TAG_HISTORY);
-                serializer.attribute(null, ATTR_VERSION, String.valueOf(CURRENT_VERSION));
+                serializer.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
                 if (intervalOverflowMillis != 0) {
-                    serializer.attribute(null, ATTR_OVERFLOW,
-                            Long.toString(intervalOverflowMillis));
+                    serializer.attributeLong(null, ATTR_OVERFLOW, intervalOverflowMillis);
                 }
                 if (allOps != null) {
                     final int opsCount = allOps.size();
@@ -1461,10 +1461,10 @@
         }
 
         private void writeHistoricalOpDLocked(@NonNull HistoricalOps ops,
-                @NonNull XmlSerializer serializer) throws IOException {
+                @NonNull TypedXmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_OPS);
-            serializer.attribute(null, ATTR_BEGIN_TIME, Long.toString(ops.getBeginTimeMillis()));
-            serializer.attribute(null, ATTR_END_TIME, Long.toString(ops.getEndTimeMillis()));
+            serializer.attributeLong(null, ATTR_BEGIN_TIME, ops.getBeginTimeMillis());
+            serializer.attributeLong(null, ATTR_END_TIME, ops.getEndTimeMillis());
             final int uidCount = ops.getUidCount();
             for (int i = 0; i < uidCount; i++) {
                 final HistoricalUidOps uidOp = ops.getUidOpsAt(i);
@@ -1474,9 +1474,9 @@
         }
 
         private void writeHistoricalUidOpsDLocked(@NonNull HistoricalUidOps uidOps,
-                @NonNull XmlSerializer serializer) throws IOException {
+                @NonNull TypedXmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_UID);
-            serializer.attribute(null, ATTR_NAME, Integer.toString(uidOps.getUid()));
+            serializer.attributeInt(null, ATTR_NAME, uidOps.getUid());
             final int packageCount = uidOps.getPackageCount();
             for (int i = 0; i < packageCount; i++) {
                 final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(i);
@@ -1486,7 +1486,7 @@
         }
 
         private void writeHistoricalPackageOpsDLocked(@NonNull HistoricalPackageOps packageOps,
-                @NonNull XmlSerializer serializer) throws IOException {
+                @NonNull TypedXmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_PACKAGE);
             serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
             final int numAttributions = packageOps.getAttributedOpsCount();
@@ -1499,7 +1499,7 @@
 
         private void writeHistoricalAttributionOpsDLocked(
                 @NonNull AppOpsManager.AttributedHistoricalOps attributionOps,
-                @NonNull XmlSerializer serializer) throws IOException {
+                @NonNull TypedXmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_ATTRIBUTION);
             XmlUtils.writeStringAttribute(serializer, ATTR_NAME, attributionOps.getTag());
             final int opCount = attributionOps.getOpCount();
@@ -1511,13 +1511,13 @@
         }
 
         private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
-                @NonNull XmlSerializer serializer) throws IOException {
+                @NonNull TypedXmlSerializer serializer) throws IOException {
             final LongSparseArray keys = op.collectKeys();
             if (keys == null || keys.size() <= 0) {
                 return;
             }
             serializer.startTag(null, TAG_OP);
-            serializer.attribute(null, ATTR_NAME, Integer.toString(op.getOpCode()));
+            serializer.attributeInt(null, ATTR_NAME, op.getOpCode());
             final int keyCount = keys.size();
             for (int i = 0; i < keyCount; i++) {
                 writeStateOnLocked(op, keys.keyAt(i), serializer);
@@ -1526,7 +1526,7 @@
         }
 
         private void writeStateOnLocked(@NonNull HistoricalOp op, long key,
-                @NonNull XmlSerializer serializer) throws IOException {
+                @NonNull TypedXmlSerializer serializer) throws IOException {
             final int uidState = AppOpsManager.extractUidStateFromKey(key);
             final int flags = AppOpsManager.extractFlagsFromKey(key);
 
@@ -1539,15 +1539,15 @@
             }
 
             serializer.startTag(null, TAG_STATE);
-            serializer.attribute(null, ATTR_NAME, Long.toString(key));
+            serializer.attributeLong(null, ATTR_NAME, key);
             if (accessCount > 0) {
-                serializer.attribute(null, ATTR_ACCESS_COUNT, Long.toString(accessCount));
+                serializer.attributeLong(null, ATTR_ACCESS_COUNT, accessCount);
             }
             if (rejectCount > 0) {
-                serializer.attribute(null, ATTR_REJECT_COUNT, Long.toString(rejectCount));
+                serializer.attributeLong(null, ATTR_REJECT_COUNT, rejectCount);
             }
             if (accessDuration > 0) {
-                serializer.attribute(null, ATTR_ACCESS_DURATION, Long.toString(accessDuration));
+                serializer.attributeLong(null, ATTR_ACCESS_DURATION, accessDuration);
             }
             serializer.endTag(null, TAG_STATE);
         }
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index efc025d..e4d9052 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -142,6 +142,7 @@
             @NonNull PromptInfo promptInfo,
             boolean debugEnabled,
             @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) {
+        Slog.d(TAG, "Creating AuthSession with: " + preAuthInfo);
         mContext = context;
         mStatusBarService = statusBarService;
         mSysuiReceiver = sysuiReceiver;
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a471664..0194259 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -500,7 +500,11 @@
 
             final List<SensorPropertiesInternal> sensors = new ArrayList<>();
             for (BiometricSensor sensor : mSensors) {
-                sensors.add(sensor.impl.getSensorProperties(opPackageName));
+                // Explicitly re-create as the super class, since AIDL doesn't play nicely with
+                // "List<? extends SensorPropertiesInternal> ...
+                final SensorPropertiesInternal prop = SensorPropertiesInternal
+                        .from(sensor.impl.getSensorProperties(opPackageName));
+                sensors.add(prop);
             }
 
             return sensors;
@@ -1043,7 +1047,7 @@
                 final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();
 
                 Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first
-                        + "), status(" + preAuthStatus.second + ")");
+                        + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo);
 
                 if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) {
                     // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index ff410fc..0943c9ca 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -49,7 +49,7 @@
 
     private final boolean mIsStrongBiometric;
     private final boolean mRequireConfirmation;
-    private final IActivityTaskManager mActivityTaskManager;
+    private final ActivityTaskManager mActivityTaskManager;
     @Nullable private final TaskStackListener mTaskStackListener;
     private final LockoutTracker mLockoutTracker;
     private final boolean mIsRestricted;
@@ -71,7 +71,7 @@
         mIsStrongBiometric = isStrongBiometric;
         mOperationId = operationId;
         mRequireConfirmation = requireConfirmation;
-        mActivityTaskManager = ActivityTaskManager.getService();
+        mActivityTaskManager = ActivityTaskManager.getInstance();
         mTaskStackListener = taskStackListener;
         mLockoutTracker = lockoutTracker;
         mIsRestricted = restricted;
@@ -146,29 +146,24 @@
             // Ensure authentication only succeeds if the client activity is on top or is keyguard.
             boolean isBackgroundAuth = false;
             if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) {
-                try {
-                    final List<ActivityManager.RunningTaskInfo> tasks =
-                            mActivityTaskManager.getTasks(1);
-                    if (tasks == null || tasks.isEmpty()) {
-                        Slog.e(TAG, "No running tasks reported");
+                final List<ActivityManager.RunningTaskInfo> tasks =
+                        mActivityTaskManager.getTasks(1);
+                if (tasks == null || tasks.isEmpty()) {
+                    Slog.e(TAG, "No running tasks reported");
+                    isBackgroundAuth = true;
+                } else {
+                    final ComponentName topActivity = tasks.get(0).topActivity;
+                    if (topActivity == null) {
+                        Slog.e(TAG, "Unable to get top activity");
                         isBackgroundAuth = true;
                     } else {
-                        final ComponentName topActivity = tasks.get(0).topActivity;
-                        if (topActivity == null) {
-                            Slog.e(TAG, "Unable to get top activity");
+                        final String topPackage = topActivity.getPackageName();
+                        if (!topPackage.contentEquals(getOwnerString())) {
+                            Slog.e(TAG, "Background authentication detected, top: " + topPackage
+                                    + ", client: " + this);
                             isBackgroundAuth = true;
-                        } else {
-                            final String topPackage = topActivity.getPackageName();
-                            if (!topPackage.contentEquals(getOwnerString())) {
-                                Slog.e(TAG, "Background authentication detected, top: " + topPackage
-                                        + ", client: " + this);
-                                isBackgroundAuth = true;
-                            }
                         }
                     }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to get running tasks", e);
-                    isBackgroundAuth = true;
                 }
             }
 
@@ -198,11 +193,7 @@
                 }
 
                 if (mTaskStackListener != null) {
-                    try {
-                        mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Could not unregister task stack listener", e);
-                    }
+                    mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
                 }
 
                 final byte[] byteToken = new byte[hardwareAuthToken.size()];
@@ -290,11 +281,7 @@
         }
 
         if (mTaskStackListener != null) {
-            try {
-                mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Could not register task stack listener", e);
-            }
+            mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
         }
 
         if (DEBUG) Slog.w(TAG, "Requesting auth for " + getOwnerString());
@@ -309,11 +296,7 @@
         super.cancel();
 
         if (mTaskStackListener != null) {
-            try {
-                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Could not unregister task stack listener", e);
-            }
+            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
         }
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java b/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
index a8250ac..d588b8d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
@@ -22,6 +22,7 @@
 import android.os.AsyncTask;
 import android.os.Environment;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -80,7 +81,7 @@
     /**
      * @return
      */
-    protected abstract void parseBiometricsLocked(XmlPullParser parser)
+    protected abstract void parseBiometricsLocked(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException;
 
 
@@ -176,8 +177,7 @@
             return;
         }
         try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(in, null);
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
             parseStateLocked(parser);
 
         } catch (XmlPullParserException | IOException e) {
@@ -189,7 +189,7 @@
     }
 
     @GuardedBy("this")
-    private void parseStateLocked(XmlPullParser parser)
+    private void parseStateLocked(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
         int type;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
index d30c3c8..78e875b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
@@ -20,6 +20,8 @@
 import android.hardware.face.Face;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -29,7 +31,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -87,8 +88,7 @@
         try {
             out = destination.startWrite();
 
-            XmlSerializer serializer = Xml.newSerializer();
-            serializer.setOutput(out, "utf-8");
+            TypedXmlSerializer serializer = Xml.resolveSerializer(out);
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             serializer.startDocument(null, true);
             serializer.startTag(null, TAG_FACES);
@@ -97,9 +97,9 @@
             for (int i = 0; i < count; i++) {
                 Face f = faces.get(i);
                 serializer.startTag(null, TAG_FACE);
-                serializer.attribute(null, ATTR_FACE_ID, Integer.toString(f.getBiometricId()));
+                serializer.attributeInt(null, ATTR_FACE_ID, f.getBiometricId());
                 serializer.attribute(null, ATTR_NAME, f.getName().toString());
-                serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(f.getDeviceId()));
+                serializer.attributeLong(null, ATTR_DEVICE_ID, f.getDeviceId());
                 serializer.endTag(null, TAG_FACE);
             }
 
@@ -119,7 +119,7 @@
 
     @GuardedBy("this")
     @Override
-    protected void parseBiometricsLocked(XmlPullParser parser)
+    protected void parseBiometricsLocked(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
         int type;
@@ -132,9 +132,9 @@
             String tagName = parser.getName();
             if (tagName.equals(TAG_FACE)) {
                 String name = parser.getAttributeValue(null, ATTR_NAME);
-                String faceId = parser.getAttributeValue(null, ATTR_FACE_ID);
-                String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
-                mBiometrics.add(new Face(name, Integer.parseInt(faceId), Integer.parseInt(deviceId)));
+                int faceId = parser.getAttributeInt(null, ATTR_FACE_ID);
+                int deviceId = parser.getAttributeInt(null, ATTR_DEVICE_ID);
+                mBiometrics.add(new Face(name, faceId, deviceId));
             }
         }
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 36796b8..cec1cb8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -65,7 +65,6 @@
  * Provider for a single instance of the {@link IFace} HAL.
  */
 public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
-    private static final String TAG = "FaceProvider";
     private static final int ENROLL_TIMEOUT_SEC = 75;
 
     private boolean mTestHalEnabled;
@@ -78,7 +77,7 @@
     @NonNull private final Handler mHandler;
     @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
     @NonNull private final UsageStats mUsageStats;
-    @NonNull private final IActivityTaskManager mActivityTaskManager;
+    @NonNull private final ActivityTaskManager mActivityTaskManager;
     @NonNull private final BiometricTaskStackListener mTaskStackListener;
 
     @Nullable private IFace mDaemon;
@@ -88,7 +87,7 @@
         public void onTaskStackChanged() {
             mHandler.post(() -> {
                 for (int i = 0; i < mSensors.size(); i++) {
-                    final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+                    final ClientMonitor<?> client = mSensors.valueAt(i).getScheduler()
                             .getCurrentClient();
                     if (!(client instanceof AuthenticationClient)) {
                         Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -98,22 +97,18 @@
                         continue; // Keyguard is always allowed
                     }
 
-                    try {
-                        final List<ActivityManager.RunningTaskInfo> runningTasks =
-                                mActivityTaskManager.getTasks(1);
-                        if (!runningTasks.isEmpty()) {
-                            final String topPackage =
-                                    runningTasks.get(0).topActivity.getPackageName();
-                            if (!topPackage.contentEquals(client.getOwnerString())
-                                    && !client.isAlreadyDone()) {
-                                Slog.e(getTag(), "Stopping background authentication, top: "
-                                        + topPackage + " currentClient: " + client);
-                                mSensors.get(i).getScheduler()
-                                        .cancelAuthentication(client.getToken());
-                            }
+                    final List<ActivityManager.RunningTaskInfo> runningTasks =
+                            mActivityTaskManager.getTasks(1);
+                    if (!runningTasks.isEmpty()) {
+                        final String topPackage =
+                                runningTasks.get(0).topActivity.getPackageName();
+                        if (!topPackage.contentEquals(client.getOwnerString())
+                                && !client.isAlreadyDone()) {
+                            Slog.e(getTag(), "Stopping background authentication, top: "
+                                    + topPackage + " currentClient: " + client);
+                            mSensors.valueAt(i).getScheduler()
+                                    .cancelAuthentication(client.getToken());
                         }
-                    } catch (RemoteException e) {
-                        Slog.e(getTag(), "Unable to get running tasks", e);
                     }
                 }
             });
@@ -130,7 +125,7 @@
         mHandler = new Handler(Looper.getMainLooper());
         mUsageStats = new UsageStats(context);
         mLockoutResetDispatcher = lockoutResetDispatcher;
-        mActivityTaskManager = ActivityTaskManager.getService();
+        mActivityTaskManager = ActivityTaskManager.getInstance();
         mTaskStackListener = new BiometricTaskStackListener();
 
         for (SensorProps prop : props) {
@@ -550,12 +545,13 @@
 
         JSONObject dump = new JSONObject();
         try {
-            dump.put("service", "Face Manager");
+            dump.put("service", getTag());
 
             JSONArray sets = new JSONArray();
             for (UserInfo user : UserManager.get(mContext).getUsers()) {
                 final int userId = user.getUserHandle().getIdentifier();
-                final int c = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+                final int c = FaceUtils.getInstance(sensorId)
+                        .getBiometricsForUser(mContext, userId).size();
                 JSONObject set = new JSONObject();
                 set.put("id", userId);
                 set.put("count", c);
@@ -574,7 +570,7 @@
 
             dump.put("prints", sets);
         } catch (JSONException e) {
-            Slog.e(TAG, "dump formatting failure", e);
+            Slog.e(getTag(), "dump formatting failure", e);
         }
         pw.println(dump);
         pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
index 9707edd..fbc26c6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
@@ -24,7 +24,6 @@
 import android.hardware.keymaster.HardwareAuthToken;
 import android.os.Binder;
 import android.os.IBinder;
-import android.os.RemoteException;
 
 /**
  * Test session that provides mostly no-ops.
@@ -59,7 +58,7 @@
     public ICancellationSignal authenticate(int cookie, long operationId) {
         return new ICancellationSignal() {
             @Override
-            public void cancel() throws RemoteException {
+            public void cancel() {
                 mHalSessionCallback.onError(Error.CANCELED, 0 /* vendorCode */);
             }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index c57ab50..d384bc6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -796,7 +796,7 @@
 
         JSONObject dump = new JSONObject();
         try {
-            dump.put("service", "Face Manager");
+            dump.put("service", TAG);
 
             JSONArray sets = new JSONArray();
             for (UserInfo user : UserManager.get(mContext).getUsers()) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
index e56c8d5..671e08b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
@@ -20,6 +20,8 @@
 import android.hardware.fingerprint.Fingerprint;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -29,7 +31,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -88,8 +89,7 @@
         try {
             out = destination.startWrite();
 
-            XmlSerializer serializer = Xml.newSerializer();
-            serializer.setOutput(out, "utf-8");
+            TypedXmlSerializer serializer = Xml.resolveSerializer(out);
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             serializer.startDocument(null, true);
             serializer.startTag(null, TAG_FINGERPRINTS);
@@ -98,10 +98,10 @@
             for (int i = 0; i < count; i++) {
                 Fingerprint fp = fingerprints.get(i);
                 serializer.startTag(null, TAG_FINGERPRINT);
-                serializer.attribute(null, ATTR_FINGER_ID, Integer.toString(fp.getBiometricId()));
+                serializer.attributeInt(null, ATTR_FINGER_ID, fp.getBiometricId());
                 serializer.attribute(null, ATTR_NAME, fp.getName().toString());
-                serializer.attribute(null, ATTR_GROUP_ID, Integer.toString(fp.getGroupId()));
-                serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(fp.getDeviceId()));
+                serializer.attributeInt(null, ATTR_GROUP_ID, fp.getGroupId());
+                serializer.attributeLong(null, ATTR_DEVICE_ID, fp.getDeviceId());
                 serializer.endTag(null, TAG_FINGERPRINT);
             }
 
@@ -121,7 +121,7 @@
 
     @GuardedBy("this")
     @Override
-    protected void parseBiometricsLocked(XmlPullParser parser)
+    protected void parseBiometricsLocked(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
 
         final int outerDepth = parser.getDepth();
@@ -135,11 +135,10 @@
             String tagName = parser.getName();
             if (tagName.equals(TAG_FINGERPRINT)) {
                 String name = parser.getAttributeValue(null, ATTR_NAME);
-                String groupId = parser.getAttributeValue(null, ATTR_GROUP_ID);
-                String fingerId = parser.getAttributeValue(null, ATTR_FINGER_ID);
-                String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
-                mBiometrics.add(new Fingerprint(name, Integer.parseInt(groupId),
-                        Integer.parseInt(fingerId), Long.parseLong(deviceId)));
+                int groupId = parser.getAttributeInt(null, ATTR_GROUP_ID);
+                int fingerId = parser.getAttributeInt(null, ATTR_FINGER_ID);
+                long deviceId = parser.getAttributeLong(null, ATTR_DEVICE_ID);
+                mBiometrics.add(new Fingerprint(name, groupId, fingerId, deviceId));
             }
         }
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index db34d144..99c662a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -53,6 +53,10 @@
 import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
 import com.android.server.biometrics.sensors.fingerprint.Udfps;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -73,7 +77,7 @@
     @NonNull private final ClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
     @NonNull private final Handler mHandler;
     @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
-    @NonNull private final IActivityTaskManager mActivityTaskManager;
+    @NonNull private final ActivityTaskManager mActivityTaskManager;
     @NonNull private final BiometricTaskStackListener mTaskStackListener;
 
     @Nullable private IFingerprint mDaemon;
@@ -84,7 +88,7 @@
         public void onTaskStackChanged() {
             mHandler.post(() -> {
                 for (int i = 0; i < mSensors.size(); i++) {
-                    final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+                    final ClientMonitor<?> client = mSensors.valueAt(i).getScheduler()
                             .getCurrentClient();
                     if (!(client instanceof AuthenticationClient)) {
                         Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -94,22 +98,18 @@
                         continue; // Keyguard is always allowed
                     }
 
-                    try {
-                        final List<ActivityManager.RunningTaskInfo> runningTasks =
-                                mActivityTaskManager.getTasks(1);
-                        if (!runningTasks.isEmpty()) {
-                            final String topPackage =
-                                    runningTasks.get(0).topActivity.getPackageName();
-                            if (!topPackage.contentEquals(client.getOwnerString())
-                                    && !client.isAlreadyDone()) {
-                                Slog.e(getTag(), "Stopping background authentication, top: "
-                                        + topPackage + " currentClient: " + client);
-                                mSensors.get(i).getScheduler()
-                                        .cancelAuthentication(client.getToken());
-                            }
+                    final List<ActivityManager.RunningTaskInfo> runningTasks =
+                            mActivityTaskManager.getTasks(1);
+                    if (!runningTasks.isEmpty()) {
+                        final String topPackage =
+                                runningTasks.get(0).topActivity.getPackageName();
+                        if (!topPackage.contentEquals(client.getOwnerString())
+                                && !client.isAlreadyDone()) {
+                            Slog.e(getTag(), "Stopping background authentication, top: "
+                                    + topPackage + " currentClient: " + client);
+                            mSensors.valueAt(i).getScheduler()
+                                    .cancelAuthentication(client.getToken());
                         }
-                    } catch (RemoteException e) {
-                        Slog.e(getTag(), "Unable to get running tasks", e);
                     }
                 }
             });
@@ -125,7 +125,7 @@
         mLazyDaemon = this::getHalInstance;
         mHandler = new Handler(Looper.getMainLooper());
         mLockoutResetDispatcher = lockoutResetDispatcher;
-        mActivityTaskManager = ActivityTaskManager.getService();
+        mActivityTaskManager = ActivityTaskManager.getInstance();
         mTaskStackListener = new BiometricTaskStackListener();
 
         for (SensorProps prop : props) {
@@ -593,7 +593,42 @@
 
     @Override
     public void dumpInternal(int sensorId, @NonNull PrintWriter pw) {
+        PerformanceTracker performanceTracker =
+                PerformanceTracker.getInstanceForSensorId(sensorId);
 
+        JSONObject dump = new JSONObject();
+        try {
+            dump.put("service", getTag());
+
+            JSONArray sets = new JSONArray();
+            for (UserInfo user : UserManager.get(mContext).getUsers()) {
+                final int userId = user.getUserHandle().getIdentifier();
+                final int c = FingerprintUtils.getInstance(sensorId)
+                        .getBiometricsForUser(mContext, userId).size();
+                JSONObject set = new JSONObject();
+                set.put("id", userId);
+                set.put("count", c);
+                set.put("accept", performanceTracker.getAcceptForUser(userId));
+                set.put("reject", performanceTracker.getRejectForUser(userId));
+                set.put("acquire", performanceTracker.getAcquireForUser(userId));
+                set.put("lockout", performanceTracker.getTimedLockoutForUser(userId));
+                set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId));
+                // cryptoStats measures statistics about secure fingerprint transactions
+                // (e.g. to unlock password storage, make secure purchases, etc.)
+                set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId));
+                set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId));
+                set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId));
+                sets.put(set);
+            }
+
+            dump.put("prints", sets);
+        } catch (JSONException e) {
+            Slog.e(getTag(), "dump formatting failure", e);
+        }
+        pw.println(dump);
+        pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
+
+        mSensors.get(sensorId).getScheduler().dump(pw);
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
index d637878..ddae110 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
@@ -18,8 +18,11 @@
 
 import android.annotation.NonNull;
 import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.face.Error;
 import android.hardware.biometrics.fingerprint.ISession;
 import android.hardware.keymaster.HardwareAuthToken;
+import android.os.Binder;
+import android.os.IBinder;
 import android.util.Slog;
 
 /**
@@ -37,24 +40,32 @@
 
     @Override
     public void generateChallenge(int cookie, int timeoutSec) {
-
+        mHalSessionCallback.onChallengeGenerated(0 /* challenge */);
     }
 
     @Override
     public void revokeChallenge(int cookie, long challenge) {
-
+        mHalSessionCallback.onChallengeRevoked(challenge);
     }
 
     @Override
     public ICancellationSignal enroll(int cookie, HardwareAuthToken hat) {
-        Slog.d(TAG, "enroll");
         return null;
     }
 
     @Override
     public ICancellationSignal authenticate(int cookie, long operationId) {
-        Slog.d(TAG, "authenticate");
-        return null;
+        return new ICancellationSignal() {
+            @Override
+            public void cancel() {
+                mHalSessionCallback.onError(Error.CANCELED, 0 /* vendorCode */);
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return new Binder();
+            }
+        };
     }
 
     @Override
@@ -86,7 +97,7 @@
 
     @Override
     public void resetLockout(int cookie, HardwareAuthToken hat) {
-
+        mHalSessionCallback.onLockoutCleared();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 11372a3..7c5b7c9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -97,7 +97,7 @@
     private boolean mTestHalEnabled;
 
     final Context mContext;
-    private final IActivityTaskManager mActivityTaskManager;
+    private final ActivityTaskManager mActivityTaskManager;
     @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
     private final BiometricScheduler mScheduler;
     private final Handler mHandler;
@@ -125,20 +125,16 @@
                     return; // Keyguard is always allowed
                 }
 
-                try {
-                    final List<ActivityManager.RunningTaskInfo> runningTasks =
-                            mActivityTaskManager.getTasks(1);
-                    if (!runningTasks.isEmpty()) {
-                        final String topPackage = runningTasks.get(0).topActivity.getPackageName();
-                        if (!topPackage.contentEquals(client.getOwnerString())
-                                && !client.isAlreadyDone()) {
-                            Slog.e(TAG, "Stopping background authentication, top: "
-                                    + topPackage + " currentClient: " + client);
-                            mScheduler.cancelAuthentication(client.getToken());
-                        }
+                final List<ActivityManager.RunningTaskInfo> runningTasks =
+                        mActivityTaskManager.getTasks(1);
+                if (!runningTasks.isEmpty()) {
+                    final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+                    if (!topPackage.contentEquals(client.getOwnerString())
+                            && !client.isAlreadyDone()) {
+                        Slog.e(TAG, "Stopping background authentication, top: "
+                                + topPackage + " currentClient: " + client);
+                        mScheduler.cancelAuthentication(client.getToken());
                     }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to get running tasks", e);
                 }
             });
         }
@@ -313,7 +309,7 @@
         mContext = context;
         mScheduler = scheduler;
         mHandler = handler;
-        mActivityTaskManager = ActivityTaskManager.getService();
+        mActivityTaskManager = ActivityTaskManager.getInstance();
 
         mTaskStackListener = new BiometricTaskStackListener();
         mAuthenticatorIds = Collections.synchronizedMap(new HashMap<>());
@@ -776,7 +772,7 @@
 
         JSONObject dump = new JSONObject();
         try {
-            dump.put("service", "Fingerprint Manager");
+            dump.put("service", TAG);
 
             JSONArray sets = new JSONArray();
             for (UserInfo user : UserManager.get(mContext).getUsers()) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index a9f62d9..3270dd5 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -132,6 +132,16 @@
     // TODO: make this private with a getter.
     public NetworkCapabilities networkCapabilities;
     public final NetworkAgentConfig networkAgentConfig;
+
+    // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
+    // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
+    // not guaranteed to be current or correct, or even to exist.
+    public @Nullable Network[] declaredUnderlyingNetworks;
+
+    // Whether this network is always metered even if its underlying networks are unmetered.
+    // Only relevant if #supportsUnderlyingNetworks is true.
+    public boolean declaredMetered;
+
     // Indicates if netd has been told to create this Network. From this point on the appropriate
     // routing rules are setup and routes are added so packets can begin flowing over the Network.
     // This is a sticky bit; once set it is never cleared.
@@ -474,10 +484,16 @@
                         networkCapabilities);
     }
 
+    /** Whether this network is a VPN. */
     public boolean isVPN() {
         return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
     }
 
+    /** Whether this network might have underlying networks. Currently only true for VPNs. */
+    public boolean supportsUnderlyingNetworks() {
+        return isVPN();
+    }
+
     private int getCurrentScore(boolean pretendValidated) {
         // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
         // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bdd315d..234dcc9 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -112,7 +112,6 @@
 import com.android.internal.net.VpnInfo;
 import com.android.internal.net.VpnProfile;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.ConnectivityService;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.net.BaseNetworkObserver;
@@ -123,7 +122,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.math.BigInteger;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -153,36 +151,13 @@
 public class Vpn {
     private static final String NETWORKTYPE = "VPN";
     private static final String TAG = "Vpn";
+    private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:";
     private static final boolean LOGD = true;
 
     // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
     // the device idle allowlist during service launch and VPN bootstrap.
     private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000;
 
-    // Settings for how much of the address space should be routed so that Vpn considers
-    // "most" of the address space is routed. This is used to determine whether this Vpn
-    // should be marked with the INTERNET capability.
-    private static final long MOST_IPV4_ADDRESSES_COUNT;
-    private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
-    static {
-        // 85% of the address space must be routed for Vpn to consider this VPN to provide
-        // INTERNET access.
-        final int howManyPercentIsMost = 85;
-
-        final long twoPower32 = 1L << 32;
-        MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
-        final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
-        MOST_IPV6_ADDRESSES_COUNT = twoPower128
-                .multiply(BigInteger.valueOf(howManyPercentIsMost))
-                .divide(BigInteger.valueOf(100));
-    }
-    // How many routes to evaluate before bailing and declaring this Vpn should provide
-    // the INTERNET capability. This is necessary because computing the address space is
-    // O(n²) and this is running in the system service, so a limit is needed to alleviate
-    // the risk of attack.
-    // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
-    // is actually O(n²)+O(n²).
-    private static final int MAX_ROUTES_TO_EVALUATE = 150;
     private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME =
             Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST;
     /**
@@ -199,6 +174,7 @@
     // automated reconnection
 
     private final Context mContext;
+    private final ConnectivityManager mConnectivityManager;
     // The context is for specific user which is created from mUserId
     private final Context mUserIdContext;
     @VisibleForTesting final Dependencies mDeps;
@@ -219,6 +195,7 @@
     private final INetworkManagementService mNetd;
     @VisibleForTesting
     protected VpnConfig mConfig;
+    private final NetworkProvider mNetworkProvider;
     @VisibleForTesting
     protected NetworkAgent mNetworkAgent;
     private final Looper mLooper;
@@ -402,6 +379,7 @@
             int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
             Ikev2SessionCreator ikev2SessionCreator) {
         mContext = context;
+        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
         mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
         mDeps = deps;
         mNetd = netService;
@@ -420,13 +398,16 @@
             Log.wtf(TAG, "Problem registering observer", e);
         }
 
+        mNetworkProvider = new NetworkProvider(context, looper, VPN_PROVIDER_NAME_BASE + mUserId);
+        // This constructor is called in onUserStart and registers the provider. The provider
+        // will be unregistered in onUserStop.
+        mConnectivityManager.registerNetworkProvider(mNetworkProvider);
         mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
                 "" /* subtypeName */);
         mNetworkCapabilities = new NetworkCapabilities();
         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
         mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
-        updateCapabilities(null /* defaultNetwork */);
 
         loadAlwaysOnPackage(keyStore);
     }
@@ -444,12 +425,39 @@
      * Update current state, dispatching event to listeners.
      */
     @VisibleForTesting
+    @GuardedBy("this")
     protected void updateState(DetailedState detailedState, String reason) {
         if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
         mLegacyState = LegacyVpnInfo.stateFromNetworkInfo(detailedState);
         mNetworkInfo.setDetailedState(detailedState, reason, null);
-        if (mNetworkAgent != null) {
-            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        // TODO : only accept transitions when the agent is in the correct state (non-null for
+        // CONNECTED, DISCONNECTED and FAILED, null for CONNECTED).
+        // This will require a way for tests to pretend the VPN is connected that's not
+        // calling this method with CONNECTED.
+        // It will also require audit of where the code calls this method with DISCONNECTED
+        // with a null agent, which it was doing historically to make sure the agent is
+        // disconnected as this was a no-op if the agent was null.
+        switch (detailedState) {
+            case CONNECTED:
+                if (null != mNetworkAgent) {
+                    mNetworkAgent.markConnected();
+                }
+                break;
+            case DISCONNECTED:
+            case FAILED:
+                if (null != mNetworkAgent) {
+                    mNetworkAgent.unregister();
+                    mNetworkAgent = null;
+                }
+                break;
+            case CONNECTING:
+                if (null != mNetworkAgent) {
+                    throw new IllegalStateException("VPN can only go to CONNECTING state when"
+                            + " the agent is null.");
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal state argument " + detailedState);
         }
         updateAlwaysOnNotification(detailedState);
     }
@@ -477,7 +485,7 @@
         final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;
 
         applyUnderlyingCapabilities(
-                mContext.getSystemService(ConnectivityManager.class),
+                mConnectivityManager,
                 underlyingNetworks,
                 mNetworkCapabilities,
                 isAlwaysMetered);
@@ -487,10 +495,10 @@
 
     @VisibleForTesting
     public static void applyUnderlyingCapabilities(
-            ConnectivityManager cm,
-            Network[] underlyingNetworks,
-            NetworkCapabilities caps,
-            boolean isAlwaysMetered) {
+            @NonNull final ConnectivityManager cm,
+            @Nullable final Network[] underlyingNetworks,
+            @NonNull final NetworkCapabilities caps,
+            final boolean isAlwaysMetered) {
         int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
         int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
         int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
@@ -1017,7 +1025,7 @@
             }
             mConfig = null;
 
-            updateState(DetailedState.IDLE, "prepare");
+            updateState(DetailedState.DISCONNECTED, "prepare");
             setVpnForcedLocked(mLockdown);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -1253,7 +1261,7 @@
         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
-        mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
+        updateState(DetailedState.CONNECTING, "agentConnect");
 
         NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
         networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
@@ -1262,20 +1270,34 @@
         mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
         mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
                 mConfig.allowedApplications, mConfig.disallowedApplications));
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
-                    mNetworkInfo, mNetworkCapabilities, lp,
-                    ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig,
-                    NetworkProvider.ID_VPN) {
-                            @Override
-                            public void unwanted() {
-                                // We are user controlled, not driven by NetworkRequest.
-                            }
-                        };
-        } finally {
-            Binder.restoreCallingIdentity(token);
+
+        // Only apps targeting Q and above can explicitly declare themselves as metered.
+        // These VPNs are assumed metered unless they state otherwise.
+        if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) {
+            mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_METERED);
+        } else {
+            mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
         }
+
+        mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
+                mNetworkCapabilities, lp,
+                ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
+            @Override
+            public void unwanted() {
+                // We are user controlled, not driven by NetworkRequest.
+            }
+        };
+        Binder.withCleanCallingIdentity(() -> {
+            try {
+                mNetworkAgent.register();
+            } catch (final Exception e) {
+                // If register() throws, don't keep an unregistered agent.
+                mNetworkAgent = null;
+                throw e;
+            }
+        });
+        mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
+                ? Arrays.asList(mConfig.underlyingNetworks) : null);
         mNetworkInfo.setIsAvailable(true);
         updateState(DetailedState.CONNECTED, "agentConnect");
     }
@@ -1291,19 +1313,12 @@
 
     private void agentDisconnect(NetworkAgent networkAgent) {
         if (networkAgent != null) {
-            NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
-            networkInfo.setIsAvailable(false);
-            networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
-            networkAgent.sendNetworkInfo(networkInfo);
+            networkAgent.unregister();
         }
     }
 
     private void agentDisconnect() {
-        if (mNetworkInfo.isConnected()) {
-            mNetworkInfo.setIsAvailable(false);
-            updateState(DetailedState.DISCONNECTED, "agentDisconnect");
-            mNetworkAgent = null;
-        }
+        updateState(DetailedState.DISCONNECTED, "agentDisconnect");
     }
 
     /**
@@ -1392,6 +1407,8 @@
                     && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
                 // Keep mNetworkAgent unchanged
             } else {
+                // Initialize the state for a new agent, while keeping the old one connected
+                // in case this new connection fails.
                 mNetworkAgent = null;
                 updateState(DetailedState.CONNECTING, "establish");
                 // Set up forwarding and DNS rules.
@@ -1575,12 +1592,13 @@
                     try {
                         addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
                                 mConfig.disallowedApplications);
-                        // ConnectivityService will call {@link #updateCapabilities} and apply
-                        // those for VPN network.
                         mNetworkCapabilities.setUids(existingRanges);
                     } catch (Exception e) {
                         Log.wtf(TAG, "Failed to add restricted user to owner", e);
                     }
+                    if (mNetworkAgent != null) {
+                        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+                    }
                 }
                 setVpnForcedLocked(mLockdown);
             }
@@ -1603,12 +1621,13 @@
                         final List<UidRange> removedRanges =
                                 uidRangesForUser(userId, existingRanges);
                         existingRanges.removeAll(removedRanges);
-                        // ConnectivityService will call {@link #updateCapabilities} and
-                        // apply those for VPN network.
                         mNetworkCapabilities.setUids(existingRanges);
                     } catch (Exception e) {
                         Log.wtf(TAG, "Failed to remove restricted user to owner", e);
                     }
+                    if (mNetworkAgent != null) {
+                        mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+                    }
                 }
                 setVpnForcedLocked(mLockdown);
             }
@@ -1625,6 +1644,9 @@
 
         // Quit any active connections
         agentDisconnect();
+
+        // The provider has been registered in the constructor, which is called in onUserStart.
+        mConnectivityManager.unregisterNetworkProvider(mNetworkProvider);
     }
 
     /**
@@ -1857,6 +1879,8 @@
                 }
             }
         }
+        mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
+                ? Arrays.asList(mConfig.underlyingNetworks) : null);
         return true;
     }
 
@@ -2399,7 +2423,6 @@
             // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
             // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
             // this is considered safe.
-            final ConnectivityManager cm = ConnectivityManager.from(mContext);
             final NetworkRequest req;
 
             if (mProfile.isRestrictedToTestNetworks()) {
@@ -2418,7 +2441,7 @@
                         .build();
             }
 
-            cm.requestNetwork(req, mNetworkCallback);
+            mConnectivityManager.requestNetwork(req, mNetworkCallback);
         }
 
         private boolean isActiveNetwork(@Nullable Network network) {
@@ -2705,8 +2728,7 @@
 
             resetIkeState();
 
-            final ConnectivityManager cm = ConnectivityManager.from(mContext);
-            cm.unregisterNetworkCallback(mNetworkCallback);
+            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
 
             mExecutor.shutdown();
         }
@@ -2787,13 +2809,12 @@
             mProfile = profile;
 
             if (!TextUtils.isEmpty(mOuterInterface)) {
-                final ConnectivityManager cm = ConnectivityManager.from(mContext);
-                for (Network network : cm.getAllNetworks()) {
-                    final LinkProperties lp = cm.getLinkProperties(network);
+                for (Network network : mConnectivityManager.getAllNetworks()) {
+                    final LinkProperties lp = mConnectivityManager.getLinkProperties(network);
                     if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
-                        final NetworkInfo networkInfo = cm.getNetworkInfo(network);
-                        if (networkInfo != null) {
-                            mOuterConnection.set(networkInfo.getType());
+                        final NetworkInfo netInfo = mConnectivityManager.getNetworkInfo(network);
+                        if (netInfo != null) {
+                            mOuterConnection.set(netInfo.getType());
                             break;
                         }
                     }
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 9a1f1e5..d27cb16 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -58,12 +58,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IntPair;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -71,7 +69,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -1650,37 +1647,23 @@
 
             String tagName = parser.getName();
             if ("accounts".equals(tagName)) {
-                String listen = parser.getAttributeValue(null, XML_ATTR_LISTEN_FOR_TICKLES);
-                String versionString = parser.getAttributeValue(null, "version");
-                int version;
-                try {
-                    version = (versionString == null) ? 0 : Integer.parseInt(versionString);
-                } catch (NumberFormatException e) {
-                    version = 0;
-                }
+                boolean listen = parser.getAttributeBoolean(
+                        null, XML_ATTR_LISTEN_FOR_TICKLES, true);
+                int version = parser.getAttributeInt(null, "version", 0);
 
                 if (version < 3) {
                     mGrantSyncAdaptersAccountAccess = true;
                 }
 
-                String nextIdString = parser.getAttributeValue(null, XML_ATTR_NEXT_AUTHORITY_ID);
-                try {
-                    int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
-                    mNextAuthorityId = Math.max(mNextAuthorityId, id);
-                } catch (NumberFormatException e) {
-                    // don't care
-                }
-                String offsetString = parser.getAttributeValue(null, XML_ATTR_SYNC_RANDOM_OFFSET);
-                try {
-                    mSyncRandomOffset = (offsetString == null) ? 0 : Integer.parseInt(offsetString);
-                } catch (NumberFormatException e) {
-                    mSyncRandomOffset = 0;
-                }
+                int nextId = parser.getAttributeInt(null, XML_ATTR_NEXT_AUTHORITY_ID, 0);
+                mNextAuthorityId = Math.max(mNextAuthorityId, nextId);
+
+                mSyncRandomOffset = parser.getAttributeInt(null, XML_ATTR_SYNC_RANDOM_OFFSET, 0);
                 if (mSyncRandomOffset == 0) {
                     Random random = new Random(System.currentTimeMillis());
                     mSyncRandomOffset = random.nextInt(86400);
                 }
-                mMasterSyncAutomatically.put(0, listen == null || Boolean.parseBoolean(listen));
+                mMasterSyncAutomatically.put(0, listen);
                 eventType = parser.next();
                 AuthorityInfo authority = null;
                 PeriodicSync periodicSync = null;
@@ -1804,27 +1787,23 @@
         return writeNeeded;
     }
 
-    private void parseListenForTickles(XmlPullParser parser) {
-        String user = parser.getAttributeValue(null, XML_ATTR_USER);
+    private void parseListenForTickles(TypedXmlPullParser parser) {
         int userId = 0;
         try {
-            userId = Integer.parseInt(user);
-        } catch (NumberFormatException e) {
+            parser.getAttributeInt(null, XML_ATTR_USER);
+        } catch (XmlPullParserException e) {
             Slog.e(TAG, "error parsing the user for listen-for-tickles", e);
-        } catch (NullPointerException e) {
-            Slog.e(TAG, "the user in listen-for-tickles is null", e);
         }
-        String enabled = parser.getAttributeValue(null, XML_ATTR_ENABLED);
-        boolean listen = enabled == null || Boolean.parseBoolean(enabled);
+        boolean listen = parser.getAttributeBoolean(null, XML_ATTR_ENABLED, true);
         mMasterSyncAutomatically.put(userId, listen);
     }
 
-    private AuthorityInfo parseAuthority(XmlPullParser parser, int version,
-            AccountAuthorityValidator validator) {
+    private AuthorityInfo parseAuthority(TypedXmlPullParser parser, int version,
+            AccountAuthorityValidator validator) throws XmlPullParserException {
         AuthorityInfo authority = null;
         int id = -1;
         try {
-            id = Integer.parseInt(parser.getAttributeValue(null, "id"));
+            id = parser.getAttributeInt(null, "id");
         } catch (NumberFormatException e) {
             Slog.e(TAG, "error parsing the id of the authority", e);
         } catch (NullPointerException e) {
@@ -1832,14 +1811,13 @@
         }
         if (id >= 0) {
             String authorityName = parser.getAttributeValue(null, "authority");
-            String enabled = parser.getAttributeValue(null, XML_ATTR_ENABLED);
+            boolean enabled = parser.getAttributeBoolean(null, XML_ATTR_ENABLED, true);
             String syncable = parser.getAttributeValue(null, "syncable");
             String accountName = parser.getAttributeValue(null, "account");
             String accountType = parser.getAttributeValue(null, "type");
-            String user = parser.getAttributeValue(null, XML_ATTR_USER);
+            int userId = parser.getAttributeInt(null, XML_ATTR_USER, 0);
             String packageName = parser.getAttributeValue(null, "package");
             String className = parser.getAttributeValue(null, "class");
-            int userId = user == null ? 0 : Integer.parseInt(user);
             if (accountType == null && packageName == null) {
                 accountType = "com.google";
                 syncable = String.valueOf(AuthorityInfo.NOT_INITIALIZED);
@@ -1884,7 +1862,7 @@
                 }
             }
             if (authority != null) {
-                authority.enabled = enabled == null || Boolean.parseBoolean(enabled);
+                authority.enabled = enabled;
                 try {
                     authority.syncable = (syncable == null) ?
                             AuthorityInfo.NOT_INITIALIZED : Integer.parseInt(syncable);
@@ -1912,32 +1890,22 @@
     /**
      * Parse a periodic sync from accounts.xml. Sets the bundle to be empty.
      */
-    private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authorityInfo) {
+    private PeriodicSync parsePeriodicSync(TypedXmlPullParser parser, AuthorityInfo authorityInfo) {
         Bundle extras = new Bundle(); // Gets filled in later.
-        String periodValue = parser.getAttributeValue(null, "period");
-        String flexValue = parser.getAttributeValue(null, "flex");
-        final long period;
+        long period;
         long flextime;
         try {
-            period = Long.parseLong(periodValue);
-        } catch (NumberFormatException e) {
+            period = parser.getAttributeLong(null, "period");
+        } catch (XmlPullParserException e) {
             Slog.e(TAG, "error parsing the period of a periodic sync", e);
             return null;
-        } catch (NullPointerException e) {
-            Slog.e(TAG, "the period of a periodic sync is null", e);
-            return null;
         }
         try {
-            flextime = Long.parseLong(flexValue);
-        } catch (NumberFormatException e) {
+            flextime = parser.getAttributeLong(null, "flex");
+        } catch (XmlPullParserException e) {
             flextime = calculateDefaultFlexTime(period);
-            Slog.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue
-                    + ", using default: "
-                    + flextime);
-        } catch (NullPointerException expected) {
-            flextime = calculateDefaultFlexTime(period);
-            Slog.d(TAG, "No flex time specified for this sync, using a default. period: "
-                    + period + " flex: " + flextime);
+            Slog.e(TAG, "Error formatting value parsed for periodic sync flex, using default: "
+                    + flextime, e);
         }
         PeriodicSync periodicSync;
         periodicSync =
@@ -1949,7 +1917,7 @@
         return periodicSync;
     }
 
-    private void parseExtra(XmlPullParser parser, Bundle extras) {
+    private void parseExtra(TypedXmlPullParser parser, Bundle extras) {
         String name = parser.getAttributeValue(null, "name");
         String type = parser.getAttributeValue(null, "type");
         String value1 = parser.getAttributeValue(null, "value1");
@@ -1994,9 +1962,9 @@
             out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
             out.startTag(null, "accounts");
-            out.attribute(null, "version", Integer.toString(ACCOUNTS_VERSION));
-            out.attribute(null, XML_ATTR_NEXT_AUTHORITY_ID, Integer.toString(mNextAuthorityId));
-            out.attribute(null, XML_ATTR_SYNC_RANDOM_OFFSET, Integer.toString(mSyncRandomOffset));
+            out.attributeInt(null, "version", ACCOUNTS_VERSION);
+            out.attributeInt(null, XML_ATTR_NEXT_AUTHORITY_ID, mNextAuthorityId);
+            out.attributeInt(null, XML_ATTR_SYNC_RANDOM_OFFSET, mSyncRandomOffset);
 
             // Write the Sync Automatically flags for each user
             final int M = mMasterSyncAutomatically.size();
@@ -2004,8 +1972,8 @@
                 int userId = mMasterSyncAutomatically.keyAt(m);
                 Boolean listen = mMasterSyncAutomatically.valueAt(m);
                 out.startTag(null, XML_TAG_LISTEN_FOR_TICKLES);
-                out.attribute(null, XML_ATTR_USER, Integer.toString(userId));
-                out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(listen));
+                out.attributeInt(null, XML_ATTR_USER, userId);
+                out.attributeBoolean(null, XML_ATTR_ENABLED, listen);
                 out.endTag(null, XML_TAG_LISTEN_FOR_TICKLES);
             }
 
@@ -2014,13 +1982,13 @@
                 AuthorityInfo authority = mAuthorities.valueAt(i);
                 EndPoint info = authority.target;
                 out.startTag(null, "authority");
-                out.attribute(null, "id", Integer.toString(authority.ident));
-                out.attribute(null, XML_ATTR_USER, Integer.toString(info.userId));
-                out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(authority.enabled));
+                out.attributeInt(null, "id", authority.ident);
+                out.attributeInt(null, XML_ATTR_USER, info.userId);
+                out.attributeBoolean(null, XML_ATTR_ENABLED, authority.enabled);
                 out.attribute(null, "account", info.account.name);
                 out.attribute(null, "type", info.account.type);
                 out.attribute(null, "authority", info.provider);
-                out.attribute(null, "syncable", Integer.toString(authority.syncable));
+                out.attributeInt(null, "syncable", authority.syncable);
                 out.endTag(null, "authority");
             }
             out.endTag(null, "accounts");
diff --git a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
index 928799b..0f1e666 100644
--- a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
+++ b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
@@ -27,17 +27,14 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.time.format.DateTimeParseException;
 import java.util.ArrayDeque;
@@ -179,7 +176,7 @@
                             entry.getKey());
                     if (userSerialNumber != -1 && userDayStats.getLocalDate().isAfter(cutOffDate)) {
                         out.startTag(null, TAG_AMBIENT_BRIGHTNESS_DAY_STATS);
-                        out.attribute(null, ATTR_USER, Integer.toString(userSerialNumber));
+                        out.attributeInt(null, ATTR_USER, userSerialNumber);
                         out.attribute(null, ATTR_LOCAL_DATE,
                                 userDayStats.getLocalDate().toString());
                         StringBuilder bucketBoundariesValues = new StringBuilder();
@@ -229,7 +226,7 @@
                     }
                     tag = parser.getName();
                     if (TAG_AMBIENT_BRIGHTNESS_DAY_STATS.equals(tag)) {
-                        String userSerialNumber = parser.getAttributeValue(null, ATTR_USER);
+                        int userSerialNumber = parser.getAttributeInt(null, ATTR_USER);
                         LocalDate localDate = LocalDate.parse(
                                 parser.getAttributeValue(null, ATTR_LOCAL_DATE));
                         String[] bucketBoundaries = parser.getAttributeValue(null,
@@ -246,8 +243,7 @@
                             parsedBucketBoundaries[i] = Float.parseFloat(bucketBoundaries[i]);
                             parsedBucketStats[i] = Float.parseFloat(bucketStats[i]);
                         }
-                        int userId = mInjector.getUserId(mUserManager,
-                                Integer.parseInt(userSerialNumber));
+                        int userId = mInjector.getUserId(mUserManager, userSerialNumber);
                         if (userId != -1 && localDate.isAfter(cutOffDate)) {
                             Deque<AmbientBrightnessDayStats> userStats = getOrCreateUserStats(
                                     parsedStats, userId);
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 3ae99ef..2a0e219 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -555,22 +555,22 @@
             if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) {
                 mEvents.append(toWrite[i]);
                 out.startTag(null, TAG_EVENT);
-                out.attribute(null, ATTR_NITS, Float.toString(toWrite[i].brightness));
-                out.attribute(null, ATTR_TIMESTAMP, Long.toString(toWrite[i].timeStamp));
+                out.attributeFloat(null, ATTR_NITS, toWrite[i].brightness);
+                out.attributeLong(null, ATTR_TIMESTAMP, toWrite[i].timeStamp);
                 out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName);
-                out.attribute(null, ATTR_USER, Integer.toString(userSerialNo));
-                out.attribute(null, ATTR_BATTERY_LEVEL, Float.toString(toWrite[i].batteryLevel));
-                out.attribute(null, ATTR_NIGHT_MODE, Boolean.toString(toWrite[i].nightMode));
-                out.attribute(null, ATTR_COLOR_TEMPERATURE, Integer.toString(
-                        toWrite[i].colorTemperature));
-                out.attribute(null, ATTR_LAST_NITS,
-                        Float.toString(toWrite[i].lastBrightness));
-                out.attribute(null, ATTR_DEFAULT_CONFIG,
-                        Boolean.toString(toWrite[i].isDefaultBrightnessConfig));
-                out.attribute(null, ATTR_POWER_SAVE,
-                        Float.toString(toWrite[i].powerBrightnessFactor));
-                out.attribute(null, ATTR_USER_POINT,
-                        Boolean.toString(toWrite[i].isUserSetBrightness));
+                out.attributeInt(null, ATTR_USER, userSerialNo);
+                out.attributeFloat(null, ATTR_BATTERY_LEVEL, toWrite[i].batteryLevel);
+                out.attributeBoolean(null, ATTR_NIGHT_MODE, toWrite[i].nightMode);
+                out.attributeInt(null, ATTR_COLOR_TEMPERATURE,
+                        toWrite[i].colorTemperature);
+                out.attributeFloat(null, ATTR_LAST_NITS,
+                        toWrite[i].lastBrightness);
+                out.attributeBoolean(null, ATTR_DEFAULT_CONFIG,
+                        toWrite[i].isDefaultBrightnessConfig);
+                out.attributeFloat(null, ATTR_POWER_SAVE,
+                        toWrite[i].powerBrightnessFactor);
+                out.attributeBoolean(null, ATTR_USER_POINT,
+                        toWrite[i].isUserSetBrightness);
                 StringBuilder luxValues = new StringBuilder();
                 StringBuilder luxTimestamps = new StringBuilder();
                 for (int j = 0; j < toWrite[i].luxValues.length; ++j) {
@@ -585,8 +585,8 @@
                 out.attribute(null, ATTR_LUX_TIMESTAMPS, luxTimestamps.toString());
                 if (toWrite[i].colorValueBuckets != null
                         && toWrite[i].colorValueBuckets.length > 0) {
-                    out.attribute(null, ATTR_COLOR_SAMPLE_DURATION,
-                            Long.toString(toWrite[i].colorSampleDuration));
+                    out.attributeLong(null, ATTR_COLOR_SAMPLE_DURATION,
+                            toWrite[i].colorSampleDuration);
                     StringBuilder buckets = new StringBuilder();
                     for (int j = 0; j < toWrite[i].colorValueBuckets.length; ++j) {
                         if (j > 0) {
@@ -633,22 +633,16 @@
                 if (TAG_EVENT.equals(tag)) {
                     BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder();
 
-                    String brightness = parser.getAttributeValue(null, ATTR_NITS);
-                    builder.setBrightness(Float.parseFloat(brightness));
-                    String timestamp = parser.getAttributeValue(null, ATTR_TIMESTAMP);
-                    builder.setTimeStamp(Long.parseLong(timestamp));
+                    builder.setBrightness(parser.getAttributeFloat(null, ATTR_NITS));
+                    builder.setTimeStamp(parser.getAttributeLong(null, ATTR_TIMESTAMP));
                     builder.setPackageName(parser.getAttributeValue(null, ATTR_PACKAGE_NAME));
-                    String user = parser.getAttributeValue(null, ATTR_USER);
-                    builder.setUserId(mInjector.getUserId(mUserManager, Integer.parseInt(user)));
-                    String batteryLevel = parser.getAttributeValue(null, ATTR_BATTERY_LEVEL);
-                    builder.setBatteryLevel(Float.parseFloat(batteryLevel));
-                    String nightMode = parser.getAttributeValue(null, ATTR_NIGHT_MODE);
-                    builder.setNightMode(Boolean.parseBoolean(nightMode));
-                    String colorTemperature =
-                            parser.getAttributeValue(null, ATTR_COLOR_TEMPERATURE);
-                    builder.setColorTemperature(Integer.parseInt(colorTemperature));
-                    String lastBrightness = parser.getAttributeValue(null, ATTR_LAST_NITS);
-                    builder.setLastBrightness(Float.parseFloat(lastBrightness));
+                    builder.setUserId(mInjector.getUserId(mUserManager,
+                            parser.getAttributeInt(null, ATTR_USER)));
+                    builder.setBatteryLevel(parser.getAttributeFloat(null, ATTR_BATTERY_LEVEL));
+                    builder.setNightMode(parser.getAttributeBoolean(null, ATTR_NIGHT_MODE));
+                    builder.setColorTemperature(
+                            parser.getAttributeInt(null, ATTR_COLOR_TEMPERATURE));
+                    builder.setLastBrightness(parser.getAttributeFloat(null, ATTR_LAST_NITS));
 
                     String luxValue = parser.getAttributeValue(null, ATTR_LUX);
                     String luxTimestamp = parser.getAttributeValue(null, ATTR_LUX_TIMESTAMPS);
@@ -667,20 +661,12 @@
                     builder.setLuxValues(luxValues);
                     builder.setLuxTimestamps(luxTimestamps);
 
-                    String defaultConfig = parser.getAttributeValue(null, ATTR_DEFAULT_CONFIG);
-                    if (defaultConfig != null) {
-                        builder.setIsDefaultBrightnessConfig(Boolean.parseBoolean(defaultConfig));
-                    }
-                    String powerSave = parser.getAttributeValue(null, ATTR_POWER_SAVE);
-                    if (powerSave != null) {
-                        builder.setPowerBrightnessFactor(Float.parseFloat(powerSave));
-                    } else {
-                        builder.setPowerBrightnessFactor(1.0f);
-                    }
-                    String userPoint = parser.getAttributeValue(null, ATTR_USER_POINT);
-                    if (userPoint != null) {
-                        builder.setUserBrightnessPoint(Boolean.parseBoolean(userPoint));
-                    }
+                    builder.setIsDefaultBrightnessConfig(
+                            parser.getAttributeBoolean(null, ATTR_DEFAULT_CONFIG, false));
+                    builder.setPowerBrightnessFactor(
+                            parser.getAttributeFloat(null, ATTR_POWER_SAVE, 1.0f));
+                    builder.setUserBrightnessPoint(
+                            parser.getAttributeBoolean(null, ATTR_USER_POINT, false));
 
                     String colorSampleDurationString =
                             parser.getAttributeValue(null, ATTR_COLOR_SAMPLE_DURATION);
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index fe6500e..468d825 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -22,6 +22,7 @@
 import android.view.Display;
 import android.view.DisplayAddress;
 import android.view.DisplayCutout;
+import android.view.DisplayEventReceiver;
 import android.view.Surface;
 
 import java.util.Arrays;
@@ -333,6 +334,9 @@
      */
     public String ownerPackageName;
 
+    public DisplayEventReceiver.FrameRateOverride[] frameRateOverrides =
+            new DisplayEventReceiver.FrameRateOverride[0];
+
     public void setAssumedDensityForExternalDisplay(int width, int height) {
         densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
         // Technically, these values should be smaller than the apparent density
@@ -386,7 +390,8 @@
                 || !Objects.equals(address, other.address)
                 || !Objects.equals(deviceProductInfo, other.deviceProductInfo)
                 || ownerUid != other.ownerUid
-                || !Objects.equals(ownerPackageName, other.ownerPackageName)) {
+                || !Objects.equals(ownerPackageName, other.ownerPackageName)
+                || !Objects.equals(frameRateOverrides, other.frameRateOverrides)) {
             diff |= DIFF_OTHER;
         }
         return diff;
@@ -425,6 +430,7 @@
         state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
+        frameRateOverrides = other.frameRateOverrides;
     }
 
     // For debugging purposes
@@ -461,6 +467,10 @@
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
         }
+        sb.append(", frameRateOverride ");
+        for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) {
+            sb.append(frameRateOverride).append(" ");
+        }
         sb.append(flagsToString(flags));
         sb.append("}");
         return sb.toString();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 4e60f1f..29b413d 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -37,6 +37,9 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
@@ -83,7 +86,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.sysprop.DisplayProperties;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.IntArray;
 import android.util.Pair;
@@ -92,6 +97,7 @@
 import android.util.SparseIntArray;
 import android.util.Spline;
 import android.view.Display;
+import android.view.DisplayEventReceiver;
 import android.view.DisplayInfo;
 import android.view.IDisplayFoldListener;
 import android.view.Surface;
@@ -114,6 +120,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Consumer;
@@ -181,6 +188,7 @@
     private static final int MSG_REQUEST_TRAVERSAL = 4;
     private static final int MSG_UPDATE_VIEWPORT = 5;
     private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 6;
+    private static final int MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE = 7;
 
     private final Context mContext;
     private final DisplayManagerHandler mHandler;
@@ -357,6 +365,30 @@
     // Received notifications of the display-fold action
     private DisplayFoldListener mDisplayFoldListener;
 
+    private final boolean mAllowNonNativeRefreshRateOverride;
+
+    private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.1f;
+
+    /**
+     * Applications use {@link android.view.Display#getRefreshRate} and
+     * {@link android.view.Display.Mode#getRefreshRate} to know what is the display refresh rate.
+     * Starting with Android S, the platform might throttle down applications frame rate to a
+     * divisor of the refresh rate if it is more preferable (for example if the application called
+     * to {@link android.view.Surface#setFrameRate}).
+     * Applications will experience {@link android.view.Choreographer#postFrameCallback} callbacks
+     * and backpressure at the throttled frame rate.
+     *
+     * {@link android.view.Display#getRefreshRate} will always return the application frame rate
+     * and not the physical display refresh rate to allow applications to do frame pacing correctly.
+     *
+     * {@link android.view.Display.Mode#getRefreshRate} will return the application frame rate if
+     * compiled to a previous release and starting with Android S it will return the physical
+     * display refresh rate.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+    static final long DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE = 170503758L;
+
     public DisplayManagerService(Context context) {
         this(context, new Injector());
     }
@@ -389,6 +421,7 @@
         mCurrentUserId = UserHandle.USER_SYSTEM;
         ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
         mWideColorSpace = colorSpaces[1];
+        mAllowNonNativeRefreshRateOverride = mInjector.getAllowNonNativeRefreshRateOverride();
 
         mSystemReady = false;
     }
@@ -677,11 +710,82 @@
                 Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED, 1, UserHandle.USER_CURRENT) != 0;
     }
 
+    private DisplayInfo getDisplayInfoForFrameRateOverride(DisplayEventReceiver.FrameRateOverride[]
+            frameRateOverrides, DisplayInfo info, int callingUid) {
+        float frameRateHz = 0;
+        for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) {
+            if (frameRateOverride.uid == callingUid) {
+                frameRateHz = frameRateOverride.frameRateHz;
+                break;
+            }
+        }
+        if (frameRateHz == 0) {
+            return info;
+        }
+
+        // Override the refresh rate only if it is a divider of the current
+        // refresh rate. This calculation needs to be in sync with the native code
+        // in RefreshRateConfigs::getRefreshRateDividerForUid
+        Display.Mode currentMode = info.getMode();
+        float numPeriods = currentMode.getRefreshRate() / frameRateHz;
+        float numPeriodsRound = Math.round(numPeriods);
+        if (Math.abs(numPeriods - numPeriodsRound) > THRESHOLD_FOR_REFRESH_RATES_DIVIDERS) {
+            return info;
+        }
+        frameRateHz = currentMode.getRefreshRate() / numPeriodsRound;
+
+        DisplayInfo overriddenInfo = new DisplayInfo();
+        overriddenInfo.copyFrom(info);
+        for (Display.Mode mode : info.supportedModes) {
+            if (!mode.equalsExceptRefreshRate(currentMode)) {
+                continue;
+            }
+
+            if (mode.getRefreshRate() >= frameRateHz - THRESHOLD_FOR_REFRESH_RATES_DIVIDERS
+                    && mode.getRefreshRate()
+                    <= frameRateHz + THRESHOLD_FOR_REFRESH_RATES_DIVIDERS) {
+                if (DEBUG) {
+                    Slog.d(TAG, "found matching modeId " + mode.getModeId());
+                }
+                overriddenInfo.refreshRateOverride = mode.getRefreshRate();
+
+                if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
+                        callingUid)) {
+                    overriddenInfo.modeId = mode.getModeId();
+                }
+                return overriddenInfo;
+            }
+        }
+
+        if (mAllowNonNativeRefreshRateOverride) {
+            overriddenInfo.refreshRateOverride = frameRateHz;
+            if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
+                    callingUid)) {
+                overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes,
+                        info.supportedModes.length + 1);
+                overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1] =
+                        new Display.Mode(Display.DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE,
+                                currentMode.getPhysicalWidth(), currentMode.getPhysicalHeight(),
+                                overriddenInfo.refreshRateOverride);
+                overriddenInfo.modeId =
+                        overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1]
+                                .getModeId();
+            }
+            return overriddenInfo;
+        }
+
+
+
+        return info;
+    }
+
     private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
         synchronized (mSyncRoot) {
             LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
             if (display != null) {
-                DisplayInfo info = display.getDisplayInfoLocked();
+                DisplayInfo info =
+                        getDisplayInfoForFrameRateOverride(display.getFrameRateOverrides(),
+                                display.getDisplayInfoLocked(), callingUid);
                 if (info.hasAccess(callingUid)
                         || isUidPresentOnDisplayInternal(callingUid, displayId)) {
                     return info;
@@ -691,14 +795,15 @@
         }
     }
 
-    private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid) {
+    private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid,
+            int callingUid) {
         synchronized (mSyncRoot) {
             if (mCallbacks.get(callingPid) != null) {
                 throw new SecurityException("The calling process has already "
                         + "registered an IDisplayManagerCallback.");
             }
 
-            CallbackRecord record = new CallbackRecord(callingPid, callback);
+            CallbackRecord record = new CallbackRecord(callingPid, callingUid, callback);
             try {
                 IBinder binder = callback.asBinder();
                 binder.linkToDeath(record, 0);
@@ -1034,6 +1139,16 @@
         scheduleTraversalLocked(false);
     }
 
+    private void handleLogicalDisplayFrameRateOverridesChangedLocked(
+            @NonNull LogicalDisplay display) {
+        final int displayId = display.getDisplayIdLocked();
+        // We don't bother invalidating the display info caches here because any changes to the
+        // display info will trigger a cache invalidation inside of LogicalDisplay before we hit
+        // this point.
+        sendDisplayEventFrameRateOverrideLocked(displayId);
+        scheduleTraversalLocked(false);
+    }
+
     private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
         final int displayId = display.getDisplayIdLocked();
         mDisplayPowerControllers.delete(displayId);
@@ -1545,6 +1660,12 @@
         mHandler.sendMessage(msg);
     }
 
+    private void sendDisplayEventFrameRateOverrideLocked(int displayId) {
+        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
+                displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+        mHandler.sendMessage(msg);
+    }
+
     // Requests that performTraversals be called at a
     // later time to apply changes to surfaces and displays.
     private void scheduleTraversalLocked(boolean inTraversal) {
@@ -1558,7 +1679,7 @@
 
     // Runs on Handler thread.
     // Delivers display event notifications to callbacks.
-    private void deliverDisplayEvent(int displayId, int event) {
+    private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids, int event) {
         if (DEBUG) {
             Slog.d(TAG, "Delivering display event: displayId="
                     + displayId + ", event=" + event);
@@ -1570,12 +1691,14 @@
             count = mCallbacks.size();
             mTempCallbacks.clear();
             for (int i = 0; i < count; i++) {
-                mTempCallbacks.add(mCallbacks.valueAt(i));
+                if (uids == null || uids.contains(mCallbacks.valueAt(i).mUid)) {
+                    mTempCallbacks.add(mCallbacks.valueAt(i));
+                }
             }
         }
 
         // After releasing the lock, send the notifications out.
-        for (int i = 0; i < count; i++) {
+        for (int i = 0; i < mTempCallbacks.size(); i++) {
             mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
         }
         mTempCallbacks.clear();
@@ -1691,6 +1814,11 @@
         long getDefaultDisplayDelayTimeout() {
             return WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
         }
+
+        boolean getAllowNonNativeRefreshRateOverride() {
+            return DisplayProperties
+                    .debug_allow_non_native_refresh_rate_override().orElse(false);
+        }
     }
 
     @VisibleForTesting
@@ -1760,7 +1888,7 @@
                     break;
 
                 case MSG_DELIVER_DISPLAY_EVENT:
-                    deliverDisplayEvent(msg.arg1, msg.arg2);
+                    deliverDisplayEvent(msg.arg1, null, msg.arg2);
                     break;
 
                 case MSG_REQUEST_TRAVERSAL:
@@ -1787,6 +1915,17 @@
                 case MSG_LOAD_BRIGHTNESS_CONFIGURATION:
                     loadBrightnessConfiguration();
                     break;
+
+                case MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+                    ArraySet<Integer> uids;
+                    synchronized (mSyncRoot) {
+                        int displayId = msg.arg1;
+                        LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+                        uids = display.getPendingFrameRateOverrideUids();
+                        display.clearPendingFrameRateOverrideUids();
+                    }
+                    deliverDisplayEvent(msg.arg1, uids, msg.arg2);
+                    break;
             }
         }
     }
@@ -1810,6 +1949,10 @@
                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_SWAPPED:
                     handleLogicalDisplaySwappedLocked(display);
                     break;
+
+                case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED:
+                    handleLogicalDisplayFrameRateOverridesChangedLocked(display);
+                    break;
             }
         }
 
@@ -1823,12 +1966,14 @@
 
     private final class CallbackRecord implements DeathRecipient {
         public final int mPid;
+        public final int mUid;
         private final IDisplayManagerCallback mCallback;
 
         public boolean mWifiDisplayScanRequested;
 
-        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
+        CallbackRecord(int pid, int uid, IDisplayManagerCallback callback) {
             mPid = pid;
+            mUid = uid;
             mCallback = callback;
         }
 
@@ -1918,9 +2063,10 @@
             }
 
             final int callingPid = Binder.getCallingPid();
+            final int callingUid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                registerCallbackInternal(callback, callingPid);
+                registerCallbackInternal(callback, callingPid, callingUid);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 1aced07..329081a 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -38,6 +38,7 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.IndentingPrintWriter;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -49,6 +50,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.server.display.utils.AmbientFilter;
 import com.android.server.display.utils.AmbientFilterFactory;
+import com.android.server.utils.DeviceConfigInterface;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -68,9 +70,11 @@
     private static final boolean DEBUG = false;
 
     private static final int MSG_REFRESH_RATE_RANGE_CHANGED = 1;
-    private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
+    private static final int MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
     private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;
-    private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4;
+    private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4;
+    private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5;
+    private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6;
 
     // Special ID used to indicate that given vote is to be applied globally, rather than to a
     // specific display.
@@ -83,6 +87,13 @@
     private final Context mContext;
 
     private final DisplayModeDirectorHandler mHandler;
+    private final Injector mInjector;
+
+    private final AppRequestObserver mAppRequestObserver;
+    private final SettingsObserver mSettingsObserver;
+    private final DisplayObserver mDisplayObserver;
+    private final DeviceConfigInterface mDeviceConfig;
+    private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
 
     // A map from the display ID to the collection of votes and their priority. The latter takes
     // the form of another map from the priority to the vote itself so that each priority is
@@ -93,12 +104,8 @@
     // A map from the display ID to the default mode of that display.
     private SparseArray<Display.Mode> mDefaultModeByDisplay;
 
-    private final AppRequestObserver mAppRequestObserver;
-    private final SettingsObserver mSettingsObserver;
-    private final DisplayObserver mDisplayObserver;
     private BrightnessObserver mBrightnessObserver;
 
-    private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
     private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener;
 
     private boolean mAlwaysRespectAppRequest;
@@ -127,8 +134,14 @@
     private int mModeSwitchingType = SWITCHING_TYPE_WITHIN_GROUPS;
 
     public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
+        this(context, handler, new RealInjector());
+    }
+
+    public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
+            @NonNull Injector injector) {
         mContext = context;
         mHandler = new DisplayModeDirectorHandler(handler.getLooper());
+        mInjector = injector;
         mVotesByDisplay = new SparseArray<>();
         mSupportedModesByDisplay = new SparseArray<>();
         mDefaultModeByDisplay = new SparseArray<>();
@@ -137,6 +150,7 @@
         mDisplayObserver = new DisplayObserver(context, handler);
         mBrightnessObserver = new BrightnessObserver(context, handler);
         mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
+        mDeviceConfig = injector.getDeviceConfig();
         mAlwaysRespectAppRequest = false;
     }
 
@@ -455,6 +469,23 @@
     }
 
     /**
+     * Retrieve the Vote for the given display and priority. Intended only for testing purposes.
+     *
+     * @param displayId the display to query for
+     * @param priority the priority of the vote to return
+     * @return the vote corresponding to the given {@code displayId} and {@code priority},
+     *         or {@code null} if there isn't one
+     */
+    @VisibleForTesting
+    @Nullable
+    Vote getVote(int displayId, int priority) {
+        synchronized (mLock) {
+            SparseArray<Vote> votes = getVotesLocked(displayId);
+            return votes.get(priority);
+        }
+    }
+
+    /**
      * Print the object's state and debug information into the given stream.
      *
      * @param pw The stream to dump information to.
@@ -586,6 +617,17 @@
     }
 
     @VisibleForTesting
+    BrightnessObserver getBrightnessObserver() {
+        return mBrightnessObserver;
+    }
+
+    @VisibleForTesting
+    SettingsObserver getSettingsObserver() {
+        return mSettingsObserver;
+    }
+
+
+    @VisibleForTesting
     DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
             float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
         synchronized (mLock) {
@@ -613,16 +655,35 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
+                case MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED: {
+                    Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
+                    mBrightnessObserver.onDeviceConfigLowBrightnessThresholdsChanged(
+                            thresholds.first, thresholds.second);
+                    break;
+                }
+
+                case MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED: {
+                    int refreshRateInZone = msg.arg1;
+                    mBrightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged(
+                            refreshRateInZone);
+                    break;
+                }
+
+                case MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED: {
                     Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
 
-                    if (thresholds != null) {
-                        mBrightnessObserver.onDeviceConfigThresholdsChanged(
-                                thresholds.first, thresholds.second);
-                    } else {
-                        mBrightnessObserver.onDeviceConfigThresholdsChanged(null, null);
-                    }
+                    mBrightnessObserver.onDeviceConfigHighBrightnessThresholdsChanged(
+                            thresholds.first, thresholds.second);
+
                     break;
+                }
+
+                case MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED: {
+                    int refreshRateInZone = msg.arg1;
+                    mBrightnessObserver.onDeviceConfigRefreshRateInHighZoneChanged(
+                            refreshRateInZone);
+                    break;
+                }
 
                 case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED:
                     Float defaultPeakRefreshRate = (Float) msg.obj;
@@ -630,12 +691,6 @@
                             defaultPeakRefreshRate);
                     break;
 
-                case MSG_REFRESH_RATE_IN_ZONE_CHANGED:
-                    int refreshRateInZone = msg.arg1;
-                    mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged(
-                            refreshRateInZone);
-                    break;
-
                 case MSG_REFRESH_RATE_RANGE_CHANGED:
                     DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener =
                             (DesiredDisplayModeSpecsListener) msg.obj;
@@ -822,10 +877,11 @@
         // by all other considerations. It acts to set a default frame rate for a device.
         public static final int PRIORITY_DEFAULT_REFRESH_RATE = 0;
 
-        // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
+        // FLICKER votes for a single refresh rate like [60,60], [90,90] or null.
         // If the higher voters result is a range, it will fix the rate to a single choice.
-        // It's used to avoid rate switch in certain conditions.
-        public static final int PRIORITY_LOW_BRIGHTNESS = 1;
+        // It's used to avoid refresh rate switches in certain conditions which may result in the
+        // user seeing the display flickering when the switches occur.
+        public static final int PRIORITY_FLICKER = 1;
 
         // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
         // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
@@ -898,8 +954,8 @@
             switch (priority) {
                 case PRIORITY_DEFAULT_REFRESH_RATE:
                     return "PRIORITY_DEFAULT_REFRESH_RATE";
-                case PRIORITY_LOW_BRIGHTNESS:
-                    return "PRIORITY_LOW_BRIGHTNESS";
+                case PRIORITY_FLICKER:
+                    return "PRIORITY_FLICKER";
                 case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
                     return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
                 case PRIORITY_APP_REQUEST_REFRESH_RATE:
@@ -924,7 +980,8 @@
         }
     }
 
-    private final class SettingsObserver extends ContentObserver {
+    @VisibleForTesting
+    final class SettingsObserver extends ContentObserver {
         private final Uri mPeakRefreshRateSetting =
                 Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
         private final Uri mMinRefreshRateSetting =
@@ -949,8 +1006,7 @@
 
         public void observe() {
             final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(mPeakRefreshRateSetting, false /*notifyDescendants*/, this,
-                    UserHandle.USER_SYSTEM);
+            mInjector.registerPeakRefreshRateObserver(cr, this);
             cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
                     UserHandle.USER_SYSTEM);
             cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
@@ -971,6 +1027,13 @@
             }
         }
 
+        public void setDefaultRefreshRate(float refreshRate) {
+            synchronized (mLock) {
+                mDefaultRefreshRate = refreshRate;
+                updateRefreshRateSettingLocked();
+            }
+        }
+
         public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
             if (defaultPeakRefreshRate == null) {
                 defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
@@ -1189,6 +1252,7 @@
         @Override
         public void onDisplayChanged(int displayId) {
             updateDisplayModes(displayId);
+            // TODO: Break the coupling between DisplayObserver and BrightnessObserver.
             mBrightnessObserver.onDisplayChanged(displayId);
         }
 
@@ -1227,15 +1291,16 @@
      */
     @VisibleForTesting
     public class BrightnessObserver extends ContentObserver {
-        // TODO: brightnessfloat: change this to the float setting
-        private final Uri mDisplayBrightnessSetting =
-                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
         private final static int LIGHT_SENSOR_RATE_MS = 250;
-        private int[] mDisplayBrightnessThresholds;
-        private int[] mAmbientBrightnessThresholds;
+        private int[] mLowDisplayBrightnessThresholds;
+        private int[] mLowAmbientBrightnessThresholds;
+        private int[] mHighDisplayBrightnessThresholds;
+        private int[] mHighAmbientBrightnessThresholds;
         // valid threshold if any item from the array >= 0
-        private boolean mShouldObserveDisplayChange;
-        private boolean mShouldObserveAmbientChange;
+        private boolean mShouldObserveDisplayLowChange;
+        private boolean mShouldObserveAmbientLowChange;
+        private boolean mShouldObserveDisplayHighChange;
+        private boolean mShouldObserveAmbientHighChange;
 
         private SensorManager mSensorManager;
         private Sensor mLightSensor;
@@ -1243,46 +1308,122 @@
         // Take it as low brightness before valid sensor data comes
         private float mAmbientLux = -1.0f;
         private AmbientFilter mAmbientFilter;
+        private int mBrightness = -1;
 
         private final Context mContext;
 
-        // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
-        // refresh rate changeable and low power mode off. After initialization, these states will
+        // Enable light sensor only when mShouldObserveAmbientLowChange is true or
+        // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate
+        // changeable and low power mode off. After initialization, these states will
         // be updated from the same handler thread.
-        private boolean mScreenOn = false;
+        private boolean mDefaultDisplayOn = false;
         private boolean mRefreshRateChangeable = false;
         private boolean mLowPowerModeEnabled = false;
 
-        private int mRefreshRateInZone;
+        private int mRefreshRateInLowZone;
+        private int mRefreshRateInHighZone;
 
         BrightnessObserver(Context context, Handler handler) {
             super(handler);
             mContext = context;
-            mDisplayBrightnessThresholds = context.getResources().getIntArray(
+            mLowDisplayBrightnessThresholds = context.getResources().getIntArray(
                     R.array.config_brightnessThresholdsOfPeakRefreshRate);
-            mAmbientBrightnessThresholds = context.getResources().getIntArray(
+            mLowAmbientBrightnessThresholds = context.getResources().getIntArray(
                     R.array.config_ambientThresholdsOfPeakRefreshRate);
 
-            if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
-                throw new RuntimeException("display brightness threshold array and ambient "
-                        + "brightness threshold array have different length");
+            if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) {
+                throw new RuntimeException("display low brightness threshold array and ambient "
+                        + "brightness threshold array have different length: "
+                        + "displayBrightnessThresholds="
+                        + Arrays.toString(mLowDisplayBrightnessThresholds)
+                        + ", ambientBrightnessThresholds="
+                        + Arrays.toString(mLowAmbientBrightnessThresholds));
             }
+
+            mHighDisplayBrightnessThresholds = context.getResources().getIntArray(
+                    R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+            mHighAmbientBrightnessThresholds = context.getResources().getIntArray(
+                    R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+            if (mHighDisplayBrightnessThresholds.length
+                    != mHighAmbientBrightnessThresholds.length) {
+                throw new RuntimeException("display high brightness threshold array and ambient "
+                        + "brightness threshold array have different length: "
+                        + "displayBrightnessThresholds="
+                        + Arrays.toString(mHighDisplayBrightnessThresholds)
+                        + ", ambientBrightnessThresholds="
+                        + Arrays.toString(mHighAmbientBrightnessThresholds));
+            }
+            mRefreshRateInHighZone = context.getResources().getInteger(
+                    R.integer.config_fixedRefreshRateInHighZone);
+        }
+
+        /**
+         * @return the refresh to lock to when in a low brightness zone
+         */
+        @VisibleForTesting
+        int getRefreshRateInLowZone() {
+            return mRefreshRateInLowZone;
+        }
+
+        /**
+         * @return the display brightness thresholds for the low brightness zones
+         */
+        @VisibleForTesting
+        int[] getLowDisplayBrightnessThresholds() {
+            return mLowDisplayBrightnessThresholds;
+        }
+
+        /**
+         * @return the ambient brightness thresholds for the low brightness zones
+         */
+        @VisibleForTesting
+        int[] getLowAmbientBrightnessThresholds() {
+            return mLowAmbientBrightnessThresholds;
+        }
+
+        public void registerLightSensor(SensorManager sensorManager, Sensor lightSensor) {
+            mSensorManager = sensorManager;
+            mLightSensor = lightSensor;
+
+            mSensorManager.registerListener(mLightSensorListener,
+                    mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
         }
 
         public void observe(SensorManager sensorManager) {
             mSensorManager = sensorManager;
+            final ContentResolver cr = mContext.getContentResolver();
+            mBrightness = Settings.System.getIntForUser(cr,
+                    Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
 
             // DeviceConfig is accessible after system ready.
-            int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
-            int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();
+            int[] lowDisplayBrightnessThresholds =
+                    mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds();
+            int[] lowAmbientBrightnessThresholds =
+                    mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds();
 
-            if (brightnessThresholds != null && ambientThresholds != null
-                    && brightnessThresholds.length == ambientThresholds.length) {
-                mDisplayBrightnessThresholds = brightnessThresholds;
-                mAmbientBrightnessThresholds = ambientThresholds;
+            if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null
+                    && lowDisplayBrightnessThresholds.length
+                    == lowAmbientBrightnessThresholds.length) {
+                mLowDisplayBrightnessThresholds = lowDisplayBrightnessThresholds;
+                mLowAmbientBrightnessThresholds = lowAmbientBrightnessThresholds;
             }
 
-            mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone();
+
+            int[] highDisplayBrightnessThresholds =
+                    mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds();
+            int[] highAmbientBrightnessThresholds =
+                    mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds();
+
+            if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null
+                    && highDisplayBrightnessThresholds.length
+                    == highAmbientBrightnessThresholds.length) {
+                mHighDisplayBrightnessThresholds = highDisplayBrightnessThresholds;
+                mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds;
+            }
+
+            mRefreshRateInLowZone = mDeviceConfigDisplaySettings.getRefreshRateInLowZone();
+            mRefreshRateInHighZone = mDeviceConfigDisplaySettings.getRefreshRateInHighZone();
+
             restartObserver();
             mDeviceConfigDisplaySettings.startListening();
         }
@@ -1294,7 +1435,7 @@
                 updateSensorStatus();
                 if (!changeable) {
                     // Revoke previous vote from BrightnessObserver
-                    updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, null);
+                    updateVoteLocked(Vote.PRIORITY_FLICKER, null);
                 }
             }
         }
@@ -1306,25 +1447,48 @@
             }
         }
 
-        public void onDeviceConfigThresholdsChanged(int[] brightnessThresholds,
+        public void onDeviceConfigLowBrightnessThresholdsChanged(int[] displayThresholds,
                 int[] ambientThresholds) {
-            if (brightnessThresholds != null && ambientThresholds != null
-                    && brightnessThresholds.length == ambientThresholds.length) {
-                mDisplayBrightnessThresholds = brightnessThresholds;
-                mAmbientBrightnessThresholds = ambientThresholds;
+            if (displayThresholds != null && ambientThresholds != null
+                    && displayThresholds.length == ambientThresholds.length) {
+                mLowDisplayBrightnessThresholds = displayThresholds;
+                mLowAmbientBrightnessThresholds = ambientThresholds;
             } else {
                 // Invalid or empty. Use device default.
-                mDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+                mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray(
                         R.array.config_brightnessThresholdsOfPeakRefreshRate);
-                mAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+                mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray(
                         R.array.config_ambientThresholdsOfPeakRefreshRate);
             }
             restartObserver();
         }
 
-        public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) {
-            if (refreshRate != mRefreshRateInZone) {
-                mRefreshRateInZone = refreshRate;
+        public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) {
+            if (refreshRate != mRefreshRateInLowZone) {
+                mRefreshRateInLowZone = refreshRate;
+                restartObserver();
+            }
+        }
+
+        public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
+                int[] ambientThresholds) {
+            if (displayThresholds != null && ambientThresholds != null
+                    && displayThresholds.length == ambientThresholds.length) {
+                mHighDisplayBrightnessThresholds = displayThresholds;
+                mHighAmbientBrightnessThresholds = ambientThresholds;
+            } else {
+                // Invalid or empty. Use device default.
+                mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+                        R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+                mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+                        R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+            }
+            restartObserver();
+        }
+
+        public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) {
+            if (refreshRate != mRefreshRateInHighZone) {
+                mRefreshRateInHighZone = refreshRate;
                 restartObserver();
             }
         }
@@ -1332,48 +1496,95 @@
         public void dumpLocked(PrintWriter pw) {
             pw.println("  BrightnessObserver");
             pw.println("    mAmbientLux: " + mAmbientLux);
-            pw.println("    mRefreshRateInZone: " + mRefreshRateInZone);
+            pw.println("    mBrightness: " + mBrightness);
+            pw.println("    mDefaultDisplayOn: " + mDefaultDisplayOn);
+            pw.println("    mLowPowerModeEnabled: " + mLowPowerModeEnabled);
+            pw.println("    mRefreshRateChangeable: " + mRefreshRateChangeable);
+            pw.println("    mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange);
+            pw.println("    mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange);
+            pw.println("    mRefreshRateInLowZone: " + mRefreshRateInLowZone);
 
-            for (int d: mDisplayBrightnessThresholds) {
-                pw.println("    mDisplayBrightnessThreshold: " + d);
+            for (int d : mLowDisplayBrightnessThresholds) {
+                pw.println("    mDisplayLowBrightnessThreshold: " + d);
             }
 
-            for (int d: mAmbientBrightnessThresholds) {
-                pw.println("    mAmbientBrightnessThreshold: " + d);
+            for (int d : mLowAmbientBrightnessThresholds) {
+                pw.println("    mAmbientLowBrightnessThreshold: " + d);
+            }
+
+            pw.println("    mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange);
+            pw.println("    mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange);
+            pw.println("    mRefreshRateInHighZone: " + mRefreshRateInHighZone);
+
+            for (int d : mHighDisplayBrightnessThresholds) {
+                pw.println("    mDisplayHighBrightnessThresholds: " + d);
+            }
+
+            for (int d : mHighAmbientBrightnessThresholds) {
+                pw.println("    mAmbientHighBrightnessThresholds: " + d);
             }
 
             mLightSensorListener.dumpLocked(pw);
+
+            if (mAmbientFilter != null) {
+                IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+                ipw.setIndent("    ");
+                mAmbientFilter.dump(ipw);
+            }
         }
 
         public void onDisplayChanged(int displayId) {
             if (displayId == Display.DEFAULT_DISPLAY) {
-                onScreenOn(isDefaultDisplayOn());
+                updateDefaultDisplayState();
             }
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
             synchronized (mLock) {
-                onBrightnessChangedLocked();
+                final ContentResolver cr = mContext.getContentResolver();
+                int brightness = Settings.System.getIntForUser(cr,
+                        Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
+                if (brightness != mBrightness) {
+                    mBrightness = brightness;
+                    onBrightnessChangedLocked();
+                }
             }
         }
 
         private void restartObserver() {
-            mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
-            mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
-
             final ContentResolver cr = mContext.getContentResolver();
-            if (mShouldObserveDisplayChange) {
-                // Content Service does not check if an listener has already been registered.
-                // To ensure only one listener is registered, force an unregistration first.
-                cr.unregisterContentObserver(this);
-                cr.registerContentObserver(mDisplayBrightnessSetting,
-                        false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
+
+            if (mRefreshRateInLowZone > 0) {
+                mShouldObserveDisplayLowChange = hasValidThreshold(
+                        mLowDisplayBrightnessThresholds);
+                mShouldObserveAmbientLowChange = hasValidThreshold(
+                        mLowAmbientBrightnessThresholds);
             } else {
-                cr.unregisterContentObserver(this);
+                mShouldObserveDisplayLowChange = false;
+                mShouldObserveAmbientLowChange = false;
             }
 
-            if (mShouldObserveAmbientChange) {
+            if (mRefreshRateInHighZone > 0) {
+                mShouldObserveDisplayHighChange = hasValidThreshold(
+                        mHighDisplayBrightnessThresholds);
+                mShouldObserveAmbientHighChange = hasValidThreshold(
+                        mHighAmbientBrightnessThresholds);
+            } else {
+                mShouldObserveDisplayHighChange = false;
+                mShouldObserveAmbientHighChange = false;
+            }
+
+            if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) {
+                // Content Service does not check if an listener has already been registered.
+                // To ensure only one listener is registered, force an unregistration first.
+                mInjector.unregisterBrightnessObserver(cr, this);
+                mInjector.registerBrightnessObserver(cr, this);
+            } else {
+                mInjector.unregisterBrightnessObserver(cr, this);
+            }
+
+            if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) {
                 Resources resources = mContext.getResources();
                 String lightSensorType = resources.getString(
                         com.android.internal.R.string.config_displayLightSensorType);
@@ -1399,8 +1610,6 @@
 
                     mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res);
                     mLightSensor = lightSensor;
-
-                    onScreenOn(isDefaultDisplayOn());
                 }
             } else {
                 mAmbientFilter = null;
@@ -1419,11 +1628,7 @@
          * Checks to see if at least one value is positive, in which case it is necessary to listen
          * to value changes.
          */
-        private boolean checkShouldObserve(int[] a) {
-            if (mRefreshRateInZone <= 0) {
-                return false;
-            }
-
+        private boolean hasValidThreshold(int[] a) {
             for (int d: a) {
                 if (d >= 0) {
                     return true;
@@ -1433,13 +1638,13 @@
             return false;
         }
 
-        private boolean isInsideZone(int brightness, float lux) {
-            for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
-                int disp = mDisplayBrightnessThresholds[i];
-                int ambi = mAmbientBrightnessThresholds[i];
+        private boolean isInsideLowZone(int brightness, float lux) {
+            for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) {
+                int disp = mLowDisplayBrightnessThresholds[i];
+                int ambi = mLowAmbientBrightnessThresholds[i];
 
                 if (disp >= 0 && ambi >= 0) {
-                    if (brightness <= disp && mAmbientLux <= ambi) {
+                    if (brightness <= disp && lux <= ambi) {
                         return true;
                     }
                 } else if (disp >= 0) {
@@ -1447,7 +1652,7 @@
                         return true;
                     }
                 } else if (ambi >= 0) {
-                    if (mAmbientLux <= ambi) {
+                    if (lux <= ambi) {
                         return true;
                     }
                 }
@@ -1455,28 +1660,77 @@
 
             return false;
         }
-        // TODO: brightnessfloat: make it use float not int
-        private void onBrightnessChangedLocked() {
-            final ContentResolver cr = mContext.getContentResolver();
-            int brightness = Settings.System.getIntForUser(cr,
-                    Settings.System.SCREEN_BRIGHTNESS, -1, cr.getUserId());
 
+        private boolean isInsideHighZone(int brightness, float lux) {
+            for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) {
+                int disp = mHighDisplayBrightnessThresholds[i];
+                int ambi = mHighAmbientBrightnessThresholds[i];
+
+                if (disp >= 0 && ambi >= 0) {
+                    if (brightness >= disp && lux >= ambi) {
+                        return true;
+                    }
+                } else if (disp >= 0) {
+                    if (brightness >= disp) {
+                        return true;
+                    }
+                } else if (ambi >= 0) {
+                    if (lux >= ambi) {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+        private void onBrightnessChangedLocked() {
             Vote vote = null;
-            boolean insideZone = isInsideZone(brightness, mAmbientLux);
-            if (insideZone) {
-                vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone);
+
+            if (mBrightness < 0) {
+                // Either the setting isn't available or we shouldn't be observing yet anyways.
+                // Either way, just bail out since there's nothing we can do here.
+                return;
+            }
+
+            boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux);
+            if (insideLowZone) {
+                vote = Vote.forRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone);
+            }
+
+            boolean insideHighZone = hasValidHighZone()
+                    && isInsideHighZone(mBrightness, mAmbientLux);
+            if (insideHighZone) {
+                vote = Vote.forRefreshRates(mRefreshRateInHighZone, mRefreshRateInHighZone);
             }
 
             if (DEBUG) {
-                Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " +  mAmbientLux +
-                        ", Vote " + vote);
+                Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " +  mAmbientLux
+                        + ", Vote " + vote);
             }
-            updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+            updateVoteLocked(Vote.PRIORITY_FLICKER, vote);
         }
 
-        private void onScreenOn(boolean on) {
-            if (mScreenOn != on) {
-                mScreenOn = on;
+        private boolean hasValidLowZone() {
+            return mRefreshRateInLowZone > 0
+                    && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange);
+        }
+
+        private boolean hasValidHighZone() {
+            return mRefreshRateInHighZone > 0
+                    && (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange);
+        }
+
+        private void updateDefaultDisplayState() {
+            Display display = mContext.getSystemService(DisplayManager.class)
+                    .getDisplay(Display.DEFAULT_DISPLAY);
+            boolean defaultDisplayOn = display != null && display.getState() != Display.STATE_OFF;
+            setDefaultDisplayState(defaultDisplayOn);
+        }
+
+        @VisibleForTesting
+        public void setDefaultDisplayState(boolean on) {
+            if (mDefaultDisplayOn != on) {
+                mDefaultDisplayOn = on;
                 updateSensorStatus();
             }
         }
@@ -1486,8 +1740,8 @@
                 return;
             }
 
-            if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled
-                    && mRefreshRateChangeable) {
+            if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange)
+                     && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) {
                 mSensorManager.registerListener(mLightSensorListener,
                         mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
             } else {
@@ -1496,11 +1750,8 @@
             }
         }
 
-        private boolean isDefaultDisplayOn() {
-            final Display display = mContext.getSystemService(DisplayManager.class)
-                    .getDisplay(Display.DEFAULT_DISPLAY);
-            return display.getState() != Display.STATE_OFF
-                    && mContext.getSystemService(PowerManager.class).isInteractive();
+        private boolean isDeviceActive() {
+            return mDefaultDisplayOn && mInjector.isDeviceInteractive(mContext);
         }
 
         private final class LightSensorEventListener implements SensorEventListener {
@@ -1518,23 +1769,33 @@
                     Slog.d(TAG, "On sensor changed: " + mLastSensorData);
                 }
 
-                boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux);
-                if (zoneChanged && mLastSensorData < mAmbientLux) {
-                    // Easier to see flicker at lower brightness environment. Forget the history to
-                    // get immediate response.
-                    mAmbientFilter.clear();
+                boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
+                        mLowAmbientBrightnessThresholds);
+                boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
+                        mHighAmbientBrightnessThresholds);
+                if ((lowZoneChanged && mLastSensorData < mAmbientLux)
+                        || (highZoneChanged && mLastSensorData > mAmbientLux)) {
+                    // Easier to see flicker at lower brightness environment or high brightness
+                    // environment. Forget the history to get immediate response.
+                    if (mAmbientFilter != null) {
+                        mAmbientFilter.clear();
+                    }
                 }
 
                 long now = SystemClock.uptimeMillis();
-                mAmbientFilter.addValue(now, mLastSensorData);
+                if (mAmbientFilter != null) {
+                    mAmbientFilter.addValue(now, mLastSensorData);
+                }
 
                 mHandler.removeCallbacks(mInjectSensorEventRunnable);
                 processSensorData(now);
 
-                if (zoneChanged && mLastSensorData > mAmbientLux) {
+                if ((lowZoneChanged && mLastSensorData > mAmbientLux)
+                        || (highZoneChanged && mLastSensorData < mAmbientLux)) {
                     // Sensor may not report new event if there is no brightness change.
                     // Need to keep querying the temporal filter for the latest estimation,
-                    // until enter in higher lux zone or is interrupted by a new sensor event.
+                    // until sensor readout and filter estimation are in the same zone or
+                    // is interrupted by a new sensor event.
                     mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
                 }
             }
@@ -1549,17 +1810,19 @@
             }
 
             private void processSensorData(long now) {
-                mAmbientLux = mAmbientFilter.getEstimate(now);
+                if (mAmbientFilter != null) {
+                    mAmbientLux = mAmbientFilter.getEstimate(now);
+                } else {
+                    mAmbientLux = mLastSensorData;
+                }
 
                 synchronized (mLock) {
                     onBrightnessChangedLocked();
                 }
             }
 
-            private boolean isDifferentZone(float lux1, float lux2) {
-                for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) {
-                    final float boundary = mAmbientBrightnessThresholds[z];
-
+            private boolean isDifferentZone(float lux1, float lux2, int[] luxThresholds) {
+                for (final float boundary : luxThresholds) {
                     // Test each boundary. See if the current value and the new value are at
                     // different sides.
                     if ((lux1 <= boundary && lux2 > boundary)
@@ -1579,7 +1842,10 @@
                     processSensorData(now);
 
                     // Inject next event if there is a possible zone change.
-                    if (isDifferentZone(mLastSensorData, mAmbientLux)) {
+                    if (isDifferentZone(mLastSensorData, mAmbientLux,
+                            mLowAmbientBrightnessThresholds)
+                            || isDifferentZone(mLastSensorData, mAmbientLux,
+                            mHighAmbientBrightnessThresholds)) {
                         mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
                     }
                 }
@@ -1592,33 +1858,75 @@
         }
 
         public void startListening() {
-            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+            mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                     BackgroundThread.getExecutor(), this);
         }
 
         /*
          * Return null if no such property or wrong format (not comma separated integers).
          */
-        public int[] getBrightnessThresholds() {
+        public int[] getLowDisplayBrightnessThresholds() {
             return getIntArrayProperty(
                     DisplayManager.DeviceConfig.
-                            KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS);
+                            KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS);
         }
 
         /*
          * Return null if no such property or wrong format (not comma separated integers).
          */
-        public int[] getAmbientThresholds() {
+        public int[] getLowAmbientBrightnessThresholds() {
             return getIntArrayProperty(
                     DisplayManager.DeviceConfig.
-                            KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS);
+                            KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS);
+        }
+
+        public int getRefreshRateInLowZone() {
+            int defaultRefreshRateInZone = mContext.getResources().getInteger(
+                    R.integer.config_defaultRefreshRateInZone);
+
+            int refreshRate = mDeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE,
+                    defaultRefreshRateInZone);
+
+            return refreshRate;
+        }
+
+        /*
+         * Return null if no such property or wrong format (not comma separated integers).
+         */
+        public int[] getHighDisplayBrightnessThresholds() {
+            return getIntArrayProperty(
+                    DisplayManager.DeviceConfig
+                            .KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS);
+        }
+
+        /*
+         * Return null if no such property or wrong format (not comma separated integers).
+         */
+        public int[] getHighAmbientBrightnessThresholds() {
+            return getIntArrayProperty(
+                    DisplayManager.DeviceConfig
+                            .KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS);
+        }
+
+        public int getRefreshRateInHighZone() {
+            int defaultRefreshRateInZone = mContext.getResources().getInteger(
+                    R.integer.config_fixedRefreshRateInHighZone);
+
+            int refreshRate = mDeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE,
+                    defaultRefreshRateInZone);
+
+            return refreshRate;
         }
 
         /*
          * Return null if no such property
          */
         public Float getDefaultPeakRefreshRate() {
-            float defaultPeakRefreshRate = DeviceConfig.getFloat(
+            float defaultPeakRefreshRate = mDeviceConfig.getFloat(
                     DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                     DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1);
 
@@ -1628,36 +1936,35 @@
             return defaultPeakRefreshRate;
         }
 
-        public int getRefreshRateInZone() {
-            int defaultRefreshRateInZone = mContext.getResources().getInteger(
-                    R.integer.config_defaultRefreshRateInZone);
-
-            int refreshRate = DeviceConfig.getInt(
-                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
-                    DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE,
-                    defaultRefreshRateInZone);
-
-            return refreshRate;
-        }
-
         @Override
         public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
-            int[] brightnessThresholds = getBrightnessThresholds();
-            int[] ambientThresholds = getAmbientThresholds();
             Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();
-            int refreshRateInZone = getRefreshRateInZone();
-
-            mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
-                    new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
-                    .sendToTarget();
             mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
                     defaultPeakRefreshRate).sendToTarget();
-            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone,
-                    0).sendToTarget();
+
+            int[] lowDisplayBrightnessThresholds = getLowDisplayBrightnessThresholds();
+            int[] lowAmbientBrightnessThresholds = getLowAmbientBrightnessThresholds();
+            int refreshRateInLowZone = getRefreshRateInLowZone();
+
+            mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED,
+                    new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds))
+                    .sendToTarget();
+            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 0)
+                    .sendToTarget();
+
+            int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds();
+            int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds();
+            int refreshRateInHighZone = getRefreshRateInHighZone();
+
+            mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED,
+                    new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds))
+                    .sendToTarget();
+            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0)
+                    .sendToTarget();
         }
 
         private int[] getIntArrayProperty(String prop) {
-            String strArray = DeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
+            String strArray = mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
                     null);
 
             if (strArray != null) {
@@ -1684,4 +1991,59 @@
         }
     }
 
+    interface Injector {
+        // TODO: brightnessfloat: change this to the float setting
+        Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+        Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+
+        @NonNull
+        DeviceConfigInterface getDeviceConfig();
+
+        void registerBrightnessObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer);
+
+        void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer);
+
+        void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer);
+
+        boolean isDeviceInteractive(@NonNull Context context);
+    }
+
+    @VisibleForTesting
+    static class RealInjector implements Injector {
+
+        @Override
+        @NonNull
+        public DeviceConfigInterface getDeviceConfig() {
+            return DeviceConfigInterface.REAL;
+        }
+
+        @Override
+        public void registerBrightnessObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/,
+                    observer, UserHandle.USER_SYSTEM);
+        }
+
+        @Override
+        public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            cr.unregisterContentObserver(observer);
+        }
+
+        @Override
+        public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
+                    observer, UserHandle.USER_SYSTEM);
+        }
+
+        @Override
+        public boolean isDeviceInteractive(@NonNull Context ctx) {
+            return ctx.getSystemService(PowerManager.class).isInteractive();
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index f657858..74ea2d7 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -208,6 +208,9 @@
 
         private DisplayDeviceConfig mDisplayDeviceConfig;
 
+        private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
+                new DisplayEventReceiver.FrameRateOverride[0];
+
         LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
                 SurfaceControl.DisplayInfo info, SurfaceControl.DisplayConfig[] configs,
                 int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs,
@@ -625,6 +628,8 @@
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_hdmi_display_name);
                 }
+                mInfo.frameRateOverrides = mFrameRateOverrides;
+
                 // The display is trusted since it is created by system.
                 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
             }
@@ -882,6 +887,13 @@
             }
         }
 
+        public void onFrameRateOverridesChanged(
+                DisplayEventReceiver.FrameRateOverride[] overrides) {
+            if (updateFrameRateOverridesLocked(overrides)) {
+                updateDeviceInfoLocked();
+            }
+        }
+
         public boolean updateActiveModeLocked(int activeConfigId) {
             if (mActiveConfigId == activeConfigId) {
                 return false;
@@ -895,6 +907,16 @@
             return true;
         }
 
+        public boolean updateFrameRateOverridesLocked(
+                DisplayEventReceiver.FrameRateOverride[] overrides) {
+            if (overrides.equals(mFrameRateOverrides)) {
+                return false;
+            }
+
+            mFrameRateOverrides = overrides;
+            return true;
+        }
+
         public void requestColorModeLocked(int colorMode) {
             if (mActiveColorMode == colorMode) {
                 return;
@@ -1102,23 +1124,39 @@
     public interface DisplayEventListener {
         void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
         void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId);
+        void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+                DisplayEventReceiver.FrameRateOverride[] overrides);
+
     }
 
     public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver {
         private final DisplayEventListener mListener;
         ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) {
-            super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH);
+            super(looper, VSYNC_SOURCE_APP,
+                    EVENT_REGISTRATION_CONFIG_CHANGED_FLAG
+                            | EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG);
             mListener = listener;
         }
+
+        @Override
         public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
             mListener.onHotplug(timestampNanos, physicalDisplayId, connected);
         }
+
+        @Override
         public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
             mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId);
         }
+
+        @Override
+        public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+                DisplayEventReceiver.FrameRateOverride[] overrides) {
+            mListener.onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
+        }
     }
 
     private final class LocalDisplayEventListener implements DisplayEventListener {
+        @Override
         public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
             synchronized (getSyncRoot()) {
                 if (connected) {
@@ -1128,6 +1166,8 @@
                 }
             }
         }
+
+        @Override
         public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
             if (DEBUG) {
                 Slog.d(TAG, "onConfigChanged("
@@ -1147,5 +1187,26 @@
                 device.onActiveDisplayConfigChangedLocked(configId);
             }
         }
+
+        @Override
+        public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
+                DisplayEventReceiver.FrameRateOverride[] overrides) {
+            if (DEBUG) {
+                Slog.d(TAG, "onFrameRateOverrideChanged(timestampNanos=" + timestampNanos
+                        + ", physicalDisplayId=" + physicalDisplayId + " overrides="
+                        + Arrays.toString(overrides) + ")");
+            }
+            synchronized (getSyncRoot()) {
+                LocalDisplayDevice device = mDevices.get(physicalDisplayId);
+                if (device == null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Received frame rate override event for unhandled physical"
+                                + " display: physicalDisplayId=" + physicalDisplayId);
+                    }
+                    return;
+                }
+                device.onFrameRateOverridesChanged(overrides);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 979c3b8..d80e168 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -20,8 +20,11 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerInternal;
+import android.util.ArraySet;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.Display;
+import android.view.DisplayEventReceiver;
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -123,10 +126,27 @@
      */
     private boolean mIsEnabled = true;
 
+    /**
+     * The UID mappings for refresh rate override
+     */
+    private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides;
+
+    /**
+     * Holds a set of UIDs that their frame rate override changed and needs to be notified
+     */
+    private ArraySet<Integer> mPendingFrameRateOverrideUids;
+
+    /**
+     * Temporary frame rate override list, used when needed.
+     */
+    private final SparseArray<Float> mTempFrameRateOverride;
+
     public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
         mDisplayId = displayId;
         mLayerStack = layerStack;
         mPrimaryDisplayDevice = primaryDisplayDevice;
+        mPendingFrameRateOverrideUids = new ArraySet<>();
+        mTempFrameRateOverride = new SparseArray<>();
     }
 
     /**
@@ -179,6 +199,27 @@
     }
 
     /**
+     * Returns the frame rate overrides list
+     */
+    public DisplayEventReceiver.FrameRateOverride[] getFrameRateOverrides() {
+        return mFrameRateOverrides;
+    }
+
+    /**
+     * Returns the list of uids that needs to be updated about their frame rate override
+     */
+    public ArraySet<Integer> getPendingFrameRateOverrideUids() {
+        return mPendingFrameRateOverrideUids;
+    }
+
+    /**
+     * Clears the list of uids that needs to be updated about their frame rate override
+     */
+    public void clearPendingFrameRateOverrideUids() {
+        mPendingFrameRateOverrideUids = new ArraySet<>();
+    }
+
+    /**
      * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo)
      */
     void getNonOverrideDisplayInfoLocked(DisplayInfo outInfo) {
@@ -324,12 +365,40 @@
                     (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
             mBaseDisplayInfo.displayCutout = maskCutout ? null : deviceInfo.displayCutout;
             mBaseDisplayInfo.displayId = mDisplayId;
+            updateFrameRateOverrides(deviceInfo);
 
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo.set(null);
         }
     }
 
+    private void updateFrameRateOverrides(DisplayDeviceInfo deviceInfo) {
+        mTempFrameRateOverride.clear();
+        if (mFrameRateOverrides != null) {
+            for (DisplayEventReceiver.FrameRateOverride frameRateOverride
+                    : mFrameRateOverrides) {
+                mTempFrameRateOverride.put(frameRateOverride.uid,
+                        frameRateOverride.frameRateHz);
+            }
+        }
+        mFrameRateOverrides = deviceInfo.frameRateOverrides;
+        if (mFrameRateOverrides != null) {
+            for (DisplayEventReceiver.FrameRateOverride frameRateOverride
+                    : mFrameRateOverrides) {
+                float refreshRate = mTempFrameRateOverride.get(frameRateOverride.uid, 0f);
+                if (refreshRate == 0 || frameRateOverride.frameRateHz != refreshRate) {
+                    mTempFrameRateOverride.put(frameRateOverride.uid,
+                            frameRateOverride.frameRateHz);
+                } else {
+                    mTempFrameRateOverride.delete(frameRateOverride.uid);
+                }
+            }
+        }
+        for (int i = 0; i < mTempFrameRateOverride.size(); i++) {
+            mPendingFrameRateOverrideUids.add(mTempFrameRateOverride.keyAt(i));
+        }
+    }
+
     /**
      * Return the insets currently applied to the display.
      *
@@ -638,5 +707,7 @@
         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
         pw.println("mOverrideDisplayInfo=" + mOverrideDisplayInfo);
         pw.println("mRequestedMinimalPostProcessing=" + mRequestedMinimalPostProcessing);
+        pw.println("mFrameRateOverrides=" + Arrays.toString(mFrameRateOverrides));
+        pw.println("mPendingFrameRateOverrideUids=" + mPendingFrameRateOverrideUids);
     }
 }
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 6b74170..cdcbb4f 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -23,6 +23,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.DisplayEventReceiver;
 import android.view.DisplayInfo;
 
 import com.android.internal.util.IndentingPrintWriter;
@@ -52,6 +53,7 @@
     public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2;
     public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3;
     public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
+    public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
 
     /**
      * Temporary display info, used for comparing display configurations.
@@ -342,6 +344,8 @@
 
             mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
             display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
+            DisplayEventReceiver.FrameRateOverride[] frameRatesOverrides =
+                    display.getFrameRateOverrides();
             display.updateLocked(mDisplayDeviceRepo);
             if (!display.isValidLocked()) {
                 mLogicalDisplays.removeAt(i);
@@ -376,6 +380,9 @@
                 final int eventMsg = TextUtils.equals(oldUniqueId, newUniqueId)
                         ? LOGICAL_DISPLAY_EVENT_CHANGED : LOGICAL_DISPLAY_EVENT_SWAPPED;
                 mListener.onLogicalDisplayEventLocked(display, eventMsg);
+            } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
+                mListener.onLogicalDisplayEventLocked(display,
+                        LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
             } else {
                 // While applications shouldn't know nor care about the non-overridden info, we
                 // still need to let WindowManager know so it can update its own internal state for
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index 49f0d35..cd3a453 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -16,8 +16,6 @@
 
 package com.android.server.display;
 
-import com.android.internal.util.DumpUtils;
-
 import android.content.Context;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManager;
@@ -30,12 +28,14 @@
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
 import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.TextureView.SurfaceTextureListener;
 import android.widget.TextView;
 
+import com.android.internal.util.DumpUtils;
+
 import java.io.PrintWriter;
 
 /**
@@ -319,7 +319,7 @@
         public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
                 int width, int height) {
             mListener.onWindowCreated(surfaceTexture,
-                    mDefaultDisplayInfo.getMode().getRefreshRate(),
+                    mDefaultDisplayInfo.getRefreshRate(),
                     mDefaultDisplayInfo.presentationDeadlineNanos, mDefaultDisplayInfo.state);
         }
 
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 494dd39..b0820e8 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -25,6 +25,7 @@
 import android.util.SparseArray;
 import android.util.SparseLongArray;
 import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.view.Display;
@@ -322,7 +323,7 @@
             return;
         }
 
-        XmlPullParser parser;
+        TypedXmlPullParser parser;
         try {
             parser = Xml.resolvePullParser(is);
             loadFromXml(parser);
@@ -355,7 +356,7 @@
         }
     }
 
-    private void loadFromXml(XmlPullParser parser)
+    private void loadFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         XmlUtils.beginDocument(parser, TAG_DISPLAY_MANAGER_STATE);
         final int outerDepth = parser.getDepth();
@@ -375,7 +376,7 @@
         }
     }
 
-    private void loadRememberedWifiDisplaysFromXml(XmlPullParser parser)
+    private void loadRememberedWifiDisplaysFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -399,7 +400,7 @@
         }
     }
 
-    private void loadDisplaysFromXml(XmlPullParser parser)
+    private void loadDisplaysFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -420,7 +421,7 @@
         }
     }
 
-    private void saveToXml(XmlSerializer serializer) throws IOException {
+    private void saveToXml(TypedXmlSerializer serializer) throws IOException {
         serializer.startDocument(null, true);
         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
         serializer.startTag(null, TAG_DISPLAY_MANAGER_STATE);
@@ -491,7 +492,7 @@
             return mColorMode;
         }
 
-        public void loadFromXml(XmlPullParser parser)
+        public void loadFromXml(TypedXmlPullParser parser)
                 throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
 
@@ -503,7 +504,7 @@
             }
         }
 
-        public void saveToXml(XmlSerializer serializer) throws IOException {
+        public void saveToXml(TypedXmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_COLOR_MODE);
             serializer.text(Integer.toString(mColorMode));
             serializer.endTag(null, TAG_COLOR_MODE);
@@ -531,7 +532,8 @@
             return false;
         }
 
-        public void loadFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+        public void loadFromXml(TypedXmlPullParser parser)
+                throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                 switch (parser.getName()) {
@@ -545,7 +547,7 @@
             }
         }
 
-        private static int loadIntValue(XmlPullParser parser)
+        private static int loadIntValue(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
             try {
                 String value = parser.nextText();
@@ -555,7 +557,7 @@
             }
         }
 
-        public void saveToXml(XmlSerializer serializer) throws IOException {
+        public void saveToXml(TypedXmlSerializer serializer) throws IOException {
             if (mWidth > 0 && mHeight > 0) {
                 serializer.startTag(null, TAG_STABLE_DISPLAY_WIDTH);
                 serializer.text(Integer.toString(mWidth));
@@ -612,14 +614,14 @@
             return mConfigurations.get(userSerial);
         }
 
-        public void loadFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+        public void loadFromXml(TypedXmlPullParser parser)
+                throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                 if (TAG_BRIGHTNESS_CONFIGURATION.equals(parser.getName())) {
                     int userSerial;
                     try {
-                        userSerial = Integer.parseInt(
-                                parser.getAttributeValue(null, ATTR_USER_SERIAL));
+                        userSerial = parser.getAttributeInt(null, ATTR_USER_SERIAL);
                     } catch (NumberFormatException nfe) {
                         userSerial = -1;
                         Slog.e(TAG, "Failed to read in brightness configuration", nfe);
@@ -655,20 +657,20 @@
             }
         }
 
-        public void saveToXml(XmlSerializer serializer) throws IOException {
+        public void saveToXml(TypedXmlSerializer serializer) throws IOException {
             for (int i = 0; i < mConfigurations.size(); i++) {
                 final int userSerial = mConfigurations.keyAt(i);
                 final BrightnessConfiguration config = mConfigurations.valueAt(i);
 
                 serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATION);
-                serializer.attribute(null, ATTR_USER_SERIAL, Integer.toString(userSerial));
+                serializer.attributeInt(null, ATTR_USER_SERIAL, userSerial);
                 String packageName = mPackageNames.get(userSerial);
                 if (packageName != null) {
                     serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
                 }
                 long timestamp = mTimeStamps.get(userSerial, -1);
                 if (timestamp != -1) {
-                    serializer.attribute(null, ATTR_TIME_STAMP, Long.toString(timestamp));
+                    serializer.attributeLong(null, ATTR_TIME_STAMP, timestamp);
                 }
                 config.saveToXml(serializer);
                 serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATION);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 42dcbeb..d0e7e45 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -507,6 +507,15 @@
     static final int ALL_DEVICE_TYPES_PLAYBACK = 4;
     static final int ALL_DEVICE_TYPES_AUDIO_SYSTEM = 3;
     static final int ALL_DEVICE_TYPES_SWITCH = 2;
+    @IntDef({
+            ALL_DEVICE_TYPES_TV,
+            ALL_DEVICE_TYPES_RECORDER,
+            ALL_DEVICE_TYPES_TUNER,
+            ALL_DEVICE_TYPES_PLAYBACK,
+            ALL_DEVICE_TYPES_AUDIO_SYSTEM,
+            ALL_DEVICE_TYPES_SWITCH
+    })
+    @interface DeviceType {}
 
     static final int DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN = 6;
     static final int DEVICE_FEATURE_TV_SUPPORTS_SET_OSD_STRING = 5;
@@ -514,21 +523,51 @@
     static final int DEVICE_FEATURE_SUPPORTS_SET_AUDIO_RATE = 3;
     static final int DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX = 2;
     static final int DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX = 1;
+    @IntDef({
+            DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN,
+            DEVICE_FEATURE_TV_SUPPORTS_SET_OSD_STRING,
+            DEVICE_FEATURE_SUPPORTS_DECK_CONTROL,
+            DEVICE_FEATURE_SUPPORTS_SET_AUDIO_RATE,
+            DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX,
+            DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX
+    })
+    @interface DeviceFeature {}
 
     static final int RC_PROFILE_TV = 0;
     static final int RC_PROFILE_SOURCE = 1;
+    @IntDef({
+            RC_PROFILE_TV,
+            RC_PROFILE_SOURCE
+    })
+    @interface RcProfile {}
 
     static final int RC_PROFILE_TV_NONE = 0x0;
     static final int RC_PROFILE_TV_ONE = 0x2;
     static final int RC_PROFILE_TV_TWO = 0x6;
     static final int RC_PROFILE_TV_THREE = 0xA;
     static final int RC_PROFILE_TV_FOUR = 0xE;
+    @IntDef({
+            RC_PROFILE_TV_NONE,
+            RC_PROFILE_TV_ONE,
+            RC_PROFILE_TV_TWO,
+            RC_PROFILE_TV_THREE,
+            RC_PROFILE_TV_FOUR
+    })
+    @interface RcProfileTv {}
 
     static final int RC_PROFILE_SOURCE_HANDLES_ROOT_MENU = 4;
     static final int RC_PROFILE_SOURCE_HANDLES_SETUP_MENU = 3;
     static final int RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU = 2;
     static final int RC_PROFILE_SOURCE_HANDLES_TOP_MENU = 1;
     static final int RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU = 0;
+    @IntDef({
+            RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+            RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+            RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+            RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+            RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU
+    })
+    @interface RcProfileSource {}
 
     private Constants() {
         /* cannot be instantiated */
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 0566d32..2374ece 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -22,12 +22,19 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.database.ContentObserver;
 import android.hardware.hdmi.HdmiControlManager;
+import android.net.Uri;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -85,9 +92,26 @@
 
     @NonNull private final Context mContext;
     @NonNull private final StorageAdapter mStorageAdapter;
-    @Nullable private final CecSettings mSystemConfig;
+    @Nullable private final CecSettings mProductConfig;
     @Nullable private final CecSettings mVendorOverride;
 
+    private final ArrayMap<Setting, Set<SettingChangeListener>>
+            mSettingChangeListeners = new ArrayMap<>();
+
+    private SettingsObserver mSettingsObserver;
+
+    /**
+     * Listener used to get notifications when value of a setting changes.
+     */
+    public interface SettingChangeListener {
+        /**
+         * Called when value of a setting changes.
+         *
+         * @param setting name of a CEC setting that changed
+         */
+        void onChange(@NonNull @CecSettingName String setting);
+    }
+
     /**
      * Setting storage input/output helper class.
      */
@@ -159,17 +183,29 @@
         }
     }
 
+    private class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            String setting = uri.getLastPathSegment();
+            HdmiCecConfig.this.notifyGlobalSettingChanged(setting);
+        }
+    }
+
     @VisibleForTesting
     HdmiCecConfig(@NonNull Context context,
                   @NonNull StorageAdapter storageAdapter,
-                  @Nullable CecSettings systemConfig,
+                  @Nullable CecSettings productConfig,
                   @Nullable CecSettings vendorOverride) {
         mContext = context;
         mStorageAdapter = storageAdapter;
-        mSystemConfig = systemConfig;
+        mProductConfig = productConfig;
         mVendorOverride = vendorOverride;
-        if (mSystemConfig == null) {
-            Slog.i(TAG, "CEC system configuration XML missing.");
+        if (mProductConfig == null) {
+            Slog.i(TAG, "CEC master configuration XML missing.");
         }
         if (mVendorOverride == null) {
             Slog.i(TAG, "CEC OEM configuration override XML missing.");
@@ -178,7 +214,7 @@
 
     HdmiCecConfig(@NonNull Context context) {
         this(context, new StorageAdapter(context),
-             readSettingsFromFile(Environment.buildPath(Environment.getRootDirectory(),
+             readSettingsFromFile(Environment.buildPath(Environment.getProductDirectory(),
                                                         ETC_DIR, CONFIG_FILE)),
              readSettingsFromFile(Environment.buildPath(Environment.getVendorDirectory(),
                                                         ETC_DIR, CONFIG_FILE)));
@@ -205,14 +241,14 @@
     @VisibleForTesting
     static HdmiCecConfig createFromStrings(@NonNull Context context,
                                            @NonNull StorageAdapter storageAdapter,
-                                           @Nullable String systemConfigXml,
+                                           @Nullable String productConfigXml,
                                            @Nullable String vendorOverrideXml) {
-        CecSettings systemConfig = null;
+        CecSettings productConfig = null;
         CecSettings vendorOverride = null;
         try {
-            if (systemConfigXml != null) {
-                systemConfig = XmlParser.read(
-                        new ByteArrayInputStream(systemConfigXml.getBytes()));
+            if (productConfigXml != null) {
+                productConfig = XmlParser.read(
+                        new ByteArrayInputStream(productConfigXml.getBytes()));
             }
             if (vendorOverrideXml != null) {
                 vendorOverride = XmlParser.read(
@@ -221,12 +257,12 @@
         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
             Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
         }
-        return new HdmiCecConfig(context, storageAdapter, systemConfig, vendorOverride);
+        return new HdmiCecConfig(context, storageAdapter, productConfig, vendorOverride);
     }
 
     @Nullable
     private Setting getSetting(@NonNull String name) {
-        if (mSystemConfig == null) {
+        if (mProductConfig == null) {
             return null;
         }
         if (mVendorOverride != null) {
@@ -237,8 +273,8 @@
                 }
             }
         }
-        // If not found, try the system config.
-        for (Setting setting : mSystemConfig.getSetting()) {
+        // If not found, try the product config.
+        for (Setting setting : mProductConfig.getSetting()) {
             if (setting.getName().equals(name)) {
                 return setting;
             }
@@ -311,6 +347,7 @@
         } else if (storage == STORAGE_SHARED_PREFS) {
             Slog.d(TAG, "Setting '" + storageKey + "' shared pref.");
             mStorageAdapter.storeSharedPref(storageKey, value);
+            notifySettingChanged(setting);
         }
     }
 
@@ -318,15 +355,112 @@
         return Integer.decode(value.getIntValue());
     }
 
+    private void notifyGlobalSettingChanged(String setting) {
+        switch (setting) {
+            case Global.HDMI_CONTROL_ENABLED:
+                notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+                break;
+            case Global.HDMI_CEC_VERSION:
+                notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION);
+                break;
+            case Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP:
+                notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
+                break;
+        }
+    }
+
+    private void notifySettingChanged(@NonNull @CecSettingName String name) {
+        Setting setting = getSetting(name);
+        if (setting == null) {
+            throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+        }
+        notifySettingChanged(setting);
+    }
+
+    private void notifySettingChanged(@NonNull Setting setting) {
+        Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
+        if (listeners == null) {
+            return;  // No listeners registered, do nothing.
+        }
+        for (SettingChangeListener listener: listeners) {
+            listener.onChange(setting.getName());
+        }
+    }
+
+    /**
+     * This method registers Global Setting change observer.
+     * Needs to be called once after initialization of HdmiCecConfig.
+     */
+    public void registerGlobalSettingsObserver(Looper looper) {
+        Handler handler = new Handler(looper);
+        mSettingsObserver = new SettingsObserver(handler);
+        ContentResolver resolver = mContext.getContentResolver();
+        String[] settings = new String[] {
+                Global.HDMI_CONTROL_ENABLED,
+                Global.HDMI_CEC_VERSION,
+                Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+        };
+        for (String setting: settings) {
+            resolver.registerContentObserver(Global.getUriFor(setting), false,
+                                             mSettingsObserver, UserHandle.USER_ALL);
+        }
+    }
+
+    /**
+     * This method unregisters Global Setting change observer.
+     */
+    public void unregisterGlobalSettingsObserver() {
+        ContentResolver resolver = mContext.getContentResolver();
+        resolver.unregisterContentObserver(mSettingsObserver);
+    }
+
+    /**
+     * Register change listener for a given setting name.
+     */
+    public void registerChangeListener(@NonNull @CecSettingName String name,
+                                       SettingChangeListener listener) {
+        Setting setting = getSetting(name);
+        if (setting == null) {
+            throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+        }
+        @Storage int storage = getStorage(setting);
+        if (storage != STORAGE_GLOBAL_SETTINGS && storage != STORAGE_SHARED_PREFS) {
+            throw new IllegalArgumentException("Change listeners for setting '" + name
+                    + "' not supported.");
+        }
+        if (!mSettingChangeListeners.containsKey(setting)) {
+            mSettingChangeListeners.put(setting, new HashSet<>());
+        }
+        mSettingChangeListeners.get(setting).add(listener);
+    }
+
+    /**
+     * Remove change listener for a given setting name.
+     */
+    public void removeChangeListener(@NonNull @CecSettingName String name,
+                                     SettingChangeListener listener) {
+        Setting setting = getSetting(name);
+        if (setting == null) {
+            throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+        }
+        if (mSettingChangeListeners.containsKey(setting)) {
+            Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
+            listeners.remove(listener);
+            if (listeners.isEmpty()) {
+                mSettingChangeListeners.remove(setting);
+            }
+        }
+    }
+
     /**
      * Returns a list of all settings based on the XML metadata.
      */
     public @CecSettingName List<String> getAllSettings() {
-        if (mSystemConfig == null) {
+        if (mProductConfig == null) {
             return new ArrayList<String>();
         }
         List<String> allSettings = new ArrayList<String>();
-        for (Setting setting : mSystemConfig.getSetting()) {
+        for (Setting setting : mProductConfig.getSetting()) {
             allSettings.add(setting.getName());
         }
         return allSettings;
@@ -336,12 +470,12 @@
      * Returns a list of user-modifiable settings based on the XML metadata.
      */
     public @CecSettingName List<String> getUserSettings() {
-        if (mSystemConfig == null) {
+        if (mProductConfig == null) {
             return new ArrayList<String>();
         }
         Set<String> userSettings = new HashSet<String>();
-        // First read from the system config.
-        for (Setting setting : mSystemConfig.getSetting()) {
+        // First read from the product config.
+        for (Setting setting : mProductConfig.getSetting()) {
             if (setting.getUserConfigurable()) {
                 userSettings.add(setting.getName());
             }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index fb71d95..9b3f788 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -554,6 +554,7 @@
         return false;
     }
 
+    @Constants.RcProfile
     protected abstract int getRcProfile();
 
     protected abstract List<Integer> getRcFeatures();
@@ -565,6 +566,11 @@
             return false;
         }
 
+        reportFeatures();
+        return true;
+    }
+
+    protected void reportFeatures() {
         List<Integer> localDeviceTypes = new ArrayList<>();
         for (HdmiCecLocalDevice localDevice : mService.getAllLocalDevices()) {
             localDeviceTypes.add(localDevice.mDeviceType);
@@ -578,7 +584,6 @@
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildReportFeatures(mAddress, mService.getCecVersion(),
                         localDeviceTypes, rcProfile, rcFeatures, deviceFeatures));
-        return true;
     }
 
     @ServiceThreadOnly
@@ -790,6 +795,9 @@
     final void handleAddressAllocated(int logicalAddress, int reason) {
         assertRunOnServiceThread();
         mAddress = mPreferredAddress = logicalAddress;
+        if (mService.getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0) {
+            reportFeatures();
+        }
         onAddressAllocated(logicalAddress, reason);
         setPreferredAddress(logicalAddress);
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 46b09dc..a945c90 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -47,8 +47,6 @@
 import com.android.server.hdmi.HdmiUtils.CodecSad;
 import com.android.server.hdmi.HdmiUtils.DeviceConfig;
 
-import com.google.android.collect.Lists;
-
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
@@ -179,7 +177,13 @@
 
     @Override
     protected List<Integer> getDeviceFeatures() {
-        return Lists.newArrayList(Constants.DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX);
+        List<Integer> deviceFeatures = new ArrayList<>();
+
+        if (SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+            deviceFeatures.add(Constants.DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX);
+        }
+
+        return deviceFeatures;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 3b3ac74..59ebdd5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -296,6 +296,7 @@
         // do nothing
     }
 
+    @Constants.RcProfile
     @Override
     protected int getRcProfile() {
         return Constants.RC_PROFILE_SOURCE;
@@ -303,10 +304,8 @@
 
     @Override
     protected List<Integer> getRcFeatures() {
-        return Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
-                Constants.RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
-                Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
-                Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU);
+        return Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+                Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 8cf6c97..ad3773e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -53,6 +53,7 @@
 
 import com.google.android.collect.Lists;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -1185,10 +1186,11 @@
         // When the device is not unplugged but reawaken from standby, we check if the System
         // Audio Control Feature is enabled or not then decide if turning SAM on/off accordingly.
         if (getAvrDeviceInfo() != null && portId == getAvrDeviceInfo().getPortId()) {
+            HdmiLogger.debug("Port ID:%d, 5v=%b", portId, connected);
             if (!connected) {
                 setSystemAudioMode(false);
-            } else if (mSystemAudioControlFeatureEnabled != mService.isSystemAudioActivated()){
-                setSystemAudioMode(mSystemAudioControlFeatureEnabled);
+            } else {
+                onNewAvrAdded(getAvrDeviceInfo());
             }
         }
 
@@ -1480,6 +1482,7 @@
         return true;
     }
 
+    @Constants.RcProfile
     @Override
     protected int getRcProfile() {
         return Constants.RC_PROFILE_TV;
@@ -1492,8 +1495,21 @@
 
     @Override
     protected List<Integer> getDeviceFeatures() {
-        return Lists.newArrayList(Constants.DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX,
-                Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN);
+        List<Integer> deviceFeatures = new ArrayList<>();
+
+        boolean hasArcPort = false;
+        List<HdmiPortInfo> ports = mService.getPortInfo();
+        for (HdmiPortInfo port : ports) {
+            if (isArcFeatureEnabled(port.getId())) {
+                hasArcPort = true;
+                break;
+            }
+        }
+        if (hasArcPort) {
+            deviceFeatures.add(Constants.DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX);
+        }
+        deviceFeatures.add(Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN);
+        return deviceFeatures;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 96303ce..0a8621b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -697,8 +697,10 @@
     }
 
     static HdmiCecMessage buildReportFeatures(int src,
-            @HdmiControlManager.HdmiCecVersion int cecVersion, List<Integer> allDeviceTypes,
-            int rcProfile, List<Integer> rcFeatures, List<Integer> deviceFeatures) {
+            @HdmiControlManager.HdmiCecVersion int cecVersion,
+            List<Integer> allDeviceTypes, @Constants.RcProfile int rcProfile,
+            List<Integer> rcFeatures,
+            List<Integer> deviceFeatures) {
         byte cecVersionByte = (byte) (cecVersion & 0xFF);
         byte deviceTypes = 0;
         for (Integer deviceType : allDeviceTypes) {
@@ -708,16 +710,16 @@
         byte rcProfileByte = 0;
         rcProfileByte |= rcProfile << 6;
         if (rcProfile == Constants.RC_PROFILE_SOURCE) {
-            for (Integer rcFeature : rcFeatures) {
+            for (@Constants.RcProfileSource Integer rcFeature : rcFeatures) {
                 rcProfileByte |= 1 << rcFeature;
             }
         } else {
-            byte rcProfileTv = (byte) (rcFeatures.get(0) & 0xFFFF);
+            @Constants.RcProfileTv byte rcProfileTv = (byte) (rcFeatures.get(0) & 0xFFFF);
             rcProfileByte |= rcProfileTv;
         }
 
         byte deviceFeaturesByte = 0;
-        for (Integer deviceFeature : deviceFeatures) {
+        for (@Constants.DeviceFeature Integer deviceFeature : deviceFeatures) {
             deviceFeaturesByte |= 1 << deviceFeature;
         }
 
@@ -777,6 +779,7 @@
         };
     }
 
+    @Constants.DeviceType
     private static int hdmiDeviceInfoDeviceTypeToShiftValue(int deviceType) {
         switch (deviceType) {
             case HdmiDeviceInfo.DEVICE_TV:
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 01ec3b4..fd825d6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -563,6 +563,7 @@
         if (mMessageValidator == null) {
             mMessageValidator = new HdmiCecMessageValidator(this);
         }
+        mHdmiCecConfig.registerGlobalSettingsObserver(mIoLooper);
     }
 
     private void bootCompleted() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index e47b544..52a804a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -25,6 +25,7 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
 import com.android.internal.util.HexDump;
@@ -571,14 +572,13 @@
         // return a list of devices config
         public static List<DeviceConfig> parse(InputStream in)
                 throws XmlPullParserException, IOException {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
-            parser.setInput(in, null);
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
             parser.nextTag();
             return readDevices(parser);
         }
 
-        private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+        private static void skip(TypedXmlPullParser parser)
+                throws XmlPullParserException, IOException {
             if (parser.getEventType() != XmlPullParser.START_TAG) {
                 throw new IllegalStateException();
             }
@@ -595,7 +595,7 @@
             }
         }
 
-        private static List<DeviceConfig> readDevices(XmlPullParser parser)
+        private static List<DeviceConfig> readDevices(TypedXmlPullParser parser)
                 throws XmlPullParserException, IOException {
             List<DeviceConfig> devices = new ArrayList<>();
 
@@ -624,7 +624,7 @@
 
         // Processes device tags in the config.
         @Nullable
-        private static DeviceConfig readDeviceConfig(XmlPullParser parser, String deviceType)
+        private static DeviceConfig readDeviceConfig(TypedXmlPullParser parser, String deviceType)
                 throws XmlPullParserException, IOException {
             List<CodecSad> codecSads = new ArrayList<>();
             int format;
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index 6633789..db93ad0 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -102,12 +102,12 @@
     }
 
     private void setArcStatus(boolean enabled) {
-        boolean wasEnabled = tv().setArcStatus(enabled);
-        Slog.i(TAG, "Change arc status [old:" + wasEnabled + ", new:" + enabled + "]");
+        tv().setArcStatus(enabled);
+        Slog.i(TAG, "Change arc status to " + enabled);
 
         // If enabled before and set to "disabled" and send <Report Arc Terminated> to
         // av reciever.
-        if (!enabled && wasEnabled) {
+        if (!enabled) {
             sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
                     mAvrAddress));
         }
diff --git a/services/core/java/com/android/server/input/ConfigurationProcessor.java b/services/core/java/com/android/server/input/ConfigurationProcessor.java
index 3888b1b..0563806 100644
--- a/services/core/java/com/android/server/input/ConfigurationProcessor.java
+++ b/services/core/java/com/android/server/input/ConfigurationProcessor.java
@@ -18,15 +18,13 @@
 
 import android.text.TextUtils;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.XmlUtils;
 
-import org.xmlpull.v1.XmlPullParser;
-
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -38,9 +36,8 @@
 
     static List<String> processExcludedDeviceNames(InputStream xml) throws Exception {
         List<String> names = new ArrayList<>();
-        try (InputStreamReader confReader = new InputStreamReader(xml)) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(confReader);
+        {
+            TypedXmlPullParser parser = Xml.resolvePullParser(xml);
             XmlUtils.beginDocument(parser, "devices");
             while (true) {
                 XmlUtils.nextElement(parser);
@@ -90,9 +87,8 @@
     static Map<String, Integer> processInputPortAssociations(InputStream xml)
             throws Exception {
         Map<String, Integer> associations = new HashMap<String, Integer>();
-        try (InputStreamReader confReader = new InputStreamReader(xml)) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(confReader);
+        {
+            TypedXmlPullParser parser = Xml.resolvePullParser(xml);
             XmlUtils.beginDocument(parser, "ports");
 
             while (true) {
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index f61662d..a735a8f 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -253,7 +253,7 @@
         }
     }
 
-    private void loadFromXml(XmlPullParser parser)
+    private void loadFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         XmlUtils.beginDocument(parser, "input-manager-state");
         final int outerDepth = parser.getDepth();
@@ -264,7 +264,7 @@
         }
     }
 
-    private void loadInputDevicesFromXml(XmlPullParser parser)
+    private void loadInputDevicesFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -285,7 +285,7 @@
         }
     }
 
-    private void saveToXml(XmlSerializer serializer) throws IOException {
+    private void saveToXml(TypedXmlSerializer serializer) throws IOException {
         serializer.startDocument(null, true);
         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
         serializer.startTag(null, "input-manager-state");
@@ -422,7 +422,7 @@
             return changed;
         }
 
-        public void loadFromXml(XmlPullParser parser)
+        public void loadFromXml(TypedXmlPullParser parser)
                 throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -505,7 +505,7 @@
             }
         }
 
-        public void saveToXml(XmlSerializer serializer) throws IOException {
+        public void saveToXml(TypedXmlSerializer serializer) throws IOException {
             for (String layout : mKeyboardLayouts) {
                 serializer.startTag(null, "keyboard-layout");
                 serializer.attribute(null, "descriptor", layout);
diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
index a077b04..24b8e34 100644
--- a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
+++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
@@ -31,17 +31,13 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.internal.util.FastXmlSerializer;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -158,20 +154,17 @@
                     final InputMethodSubtype subtype = subtypesList.get(i);
                     out.startTag(null, NODE_SUBTYPE);
                     if (subtype.hasSubtypeId()) {
-                        out.attribute(null, ATTR_IME_SUBTYPE_ID,
-                                String.valueOf(subtype.getSubtypeId()));
+                        out.attributeInt(null, ATTR_IME_SUBTYPE_ID, subtype.getSubtypeId());
                     }
-                    out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId()));
-                    out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId()));
+                    out.attributeInt(null, ATTR_ICON, subtype.getIconResId());
+                    out.attributeInt(null, ATTR_LABEL, subtype.getNameResId());
                     out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale());
                     out.attribute(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG,
                             subtype.getLanguageTag());
                     out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode());
                     out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
-                    out.attribute(null, ATTR_IS_AUXILIARY,
-                            String.valueOf(subtype.isAuxiliary() ? 1 : 0));
-                    out.attribute(null, ATTR_IS_ASCII_CAPABLE,
-                            String.valueOf(subtype.isAsciiCapable() ? 1 : 0));
+                    out.attributeInt(null, ATTR_IS_AUXILIARY, subtype.isAuxiliary() ? 1 : 0);
+                    out.attributeInt(null, ATTR_IS_ASCII_CAPABLE, subtype.isAsciiCapable() ? 1 : 0);
                     out.endTag(null, NODE_SUBTYPE);
                 }
                 out.endTag(null, NODE_IMI);
@@ -243,10 +236,8 @@
                         Slog.w(TAG, "IME uninstalled or not valid.: " + currentImiId);
                         continue;
                     }
-                    final int icon = Integer.parseInt(
-                            parser.getAttributeValue(null, ATTR_ICON));
-                    final int label = Integer.parseInt(
-                            parser.getAttributeValue(null, ATTR_LABEL));
+                    final int icon = parser.getAttributeInt(null, ATTR_ICON);
+                    final int label = parser.getAttributeInt(null, ATTR_LABEL);
                     final String imeSubtypeLocale =
                             parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE);
                     final String languageTag =
@@ -269,10 +260,10 @@
                             .setSubtypeExtraValue(imeSubtypeExtraValue)
                             .setIsAuxiliary(isAuxiliary)
                             .setIsAsciiCapable(isAsciiCapable);
-                    final String subtypeIdString =
-                            parser.getAttributeValue(null, ATTR_IME_SUBTYPE_ID);
-                    if (subtypeIdString != null) {
-                        builder.setSubtypeId(Integer.parseInt(subtypeIdString));
+                    final int subtypeId = parser.getAttributeInt(null, ATTR_IME_SUBTYPE_ID,
+                            InputMethodSubtype.SUBTYPE_ID_NONE);
+                    if (subtypeId != InputMethodSubtype.SUBTYPE_ID_NONE) {
+                        builder.setSubtypeId(subtypeId);
                     }
                     tempSubtypesArray.add(builder.build());
                 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a4844f6..6395094 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,6 +15,7 @@
 
 package com.android.server.inputmethod;
 
+import static android.inputmethodservice.InputMethodService.FINISH_INPUT_NO_FALLBACK_CONNECTION;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
 import static android.os.IServiceManager.DUMP_FLAG_PROTO;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -45,6 +46,8 @@
 import static android.util.imetracing.ImeTracing.IME_TRACING_FROM_IMMS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -118,7 +121,6 @@
 import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.IndentingPrintWriter;
-import android.util.Log;
 import android.util.LruCache;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
@@ -131,6 +133,8 @@
 import android.view.IWindowManager;
 import android.view.InputChannel;
 import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.autofill.AutofillId;
@@ -152,7 +156,10 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.inputmethod.CallbackUtils;
+import com.android.internal.inputmethod.IInputBindResultResultCallback;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodDebug;
@@ -203,6 +210,7 @@
 import java.util.WeakHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
 
 /**
  * This class provides a system service that manages input methods.
@@ -474,6 +482,7 @@
         }
     }
 
+    @GuardedBy("mMethodMap")
     final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
 
     private static final class ActivityViewInfo {
@@ -530,6 +539,13 @@
     int mCurSeq;
 
     /**
+     * {@code true} if the Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
+     *
+     * This prevents the IME from showing when it otherwise may have shown.
+     */
+    boolean mImeHiddenByDisplayPolicy;
+
+    /**
      * The client that is currently bound to an input method.
      */
     ClientState mCurClient;
@@ -708,6 +724,8 @@
      */
     boolean mIsInteractive = true;
 
+    private IPlatformCompat mPlatformCompat;
+
     int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
 
     /**
@@ -1519,12 +1537,14 @@
 
         @Override
         public void sessionCreated(IInputMethodSession session) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.sessionCreated");
             final long ident = Binder.clearCallingIdentity();
             try {
                 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -1657,7 +1677,7 @@
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
-        mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
+        mImeDisplayValidator = displayId -> mWindowManagerInternal.getDisplayImePolicy(displayId);
         mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
             @Override
             public void executeMessage(Message msg) {
@@ -1669,6 +1689,8 @@
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS);
+        mPlatformCompat = IPlatformCompat.Stub.asInterface(
+                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
         mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
         mIsLowRam = ActivityManager.isLowRamDeviceStatic();
 
@@ -2267,6 +2289,8 @@
                 }
 
                 if (mCurClient == cs) {
+                    hideCurrentInputLocked(
+                            mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
                     if (mBoundToMethod) {
                         mBoundToMethod = false;
                         if (mCurMethod != null) {
@@ -2305,8 +2329,8 @@
                 }
             }
 
-            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
-                    MSG_SET_ACTIVE, 0, 0, mCurClient));
+            scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */,
+                    false /* reportToImeController */);
             executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
                     MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
             mCurClient.sessionRequested = false;
@@ -2437,6 +2461,12 @@
         final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
                 mImeDisplayValidator);
 
+        if (displayIdToShowIme == INVALID_DISPLAY) {
+            mImeHiddenByDisplayPolicy = true;
+            return InputBindResult.NO_IME;
+        }
+        mImeHiddenByDisplayPolicy = false;
+
         if (mCurClient != cs) {
             // Was the keyguard locked when switching over to the new client?
             mCurClientInKeyguard = isKeyguardLocked();
@@ -2448,7 +2478,8 @@
 
             // If the screen is on, inform the new client it is active
             if (mIsInteractive) {
-                executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
+                scheduleSetActiveToClient(cs, true /* active */, false /* fullscreen */,
+                        false /* reportToImeController */);
             }
         }
 
@@ -2548,7 +2579,7 @@
 
     @FunctionalInterface
     interface ImeDisplayValidator {
-        boolean displayCanShowIme(int displayId);
+        @DisplayImePolicy int getDisplayImePolicy(int displayId);
     }
 
     /**
@@ -2557,7 +2588,9 @@
      * @param displayId the ID of the display where the IME client target is.
      * @param checker instance of {@link ImeDisplayValidator} which is used for
      *                checking display config to adjust the final target display.
-     * @return The ID of the display where the IME should be shown.
+     * @return The ID of the display where the IME should be shown or
+     *         {@link android.view.Display#INVALID_DISPLAY} if the display has an ImePolicy of
+     *         {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
      */
     static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
         if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
@@ -2566,7 +2599,14 @@
 
         // Show IME window on fallback display when the display doesn't support system decorations
         // or the display is virtual and isn't owned by system for security concern.
-        return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
+        final int result = checker.getDisplayImePolicy(displayId);
+        if (result == DISPLAY_IME_POLICY_LOCAL) {
+            return displayId;
+        } else if (result == DISPLAY_IME_POLICY_HIDE) {
+            return INVALID_DISPLAY;
+        } else {
+            return FALLBACK_DISPLAY_ID;
+        }
     }
 
     @AnyThread
@@ -2577,6 +2617,7 @@
 
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
         synchronized (mMethodMap) {
             if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
                 mCurMethod = IInputMethod.Stub.asInterface(service);
@@ -2592,6 +2633,7 @@
                 if (mCurToken == null) {
                     Slog.w(TAG, "Service connected without a token!");
                     unbindCurrentMethodLocked();
+                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                     return;
                 }
                 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
@@ -2605,6 +2647,7 @@
                 }
             }
         }
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
     void onSessionCreated(IInputMethod method, IInputMethodSession session,
@@ -3312,63 +3355,68 @@
 
     @NonNull
     @Override
-    public InputBindResult startInputOrWindowGainedFocus(
+    public void startInputOrWindowGainedFocus(
             @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
             @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
             int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
-            @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
-        if (windowToken == null) {
-            Slog.e(TAG, "windowToken cannot be null.");
-            return InputBindResult.NULL;
-        }
-        try {
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
-                    "IMMS.startInputOrWindowGainedFocus");
-            ImeTracing.getInstance().triggerManagerServiceDump(
-                    "InputMethodManagerService#startInputOrWindowGainedFocus");
-            final int callingUserId = UserHandle.getCallingUserId();
-            final int userId;
-            if (attribute != null && attribute.targetInputMethodUser != null
-                    && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
-                mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                        "Using EditorInfo.targetInputMethodUser requires"
-                                + " INTERACT_ACROSS_USERS_FULL.");
-                userId = attribute.targetInputMethodUser.getIdentifier();
-                if (!mUserManagerInternal.isUserRunning(userId)) {
-                    // There is a chance that we hit here because of race condition.  Let's just
-                    // return an error code instead of crashing the caller process, which at least
-                    // has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important
-                    // process.
-                    Slog.e(TAG, "User #" + userId + " is not running.");
-                    return InputBindResult.INVALID_USER;
-                }
-            } else {
-                userId = callingUserId;
-            }
-            final InputBindResult result;
-            synchronized (mMethodMap) {
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
-                            windowToken, startInputFlags, softInputMode, windowFlags, attribute,
-                            inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-            if (result == null) {
-                // This must never happen, but just in case.
-                Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
-                        + InputMethodDebug.startInputReasonToString(startInputReason)
-                        + " windowFlags=#" + Integer.toHexString(windowFlags)
-                        + " editorInfo=" + attribute);
+            @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion,
+            IInputBindResultResultCallback resultCallback) {
+        CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> {
+            if (windowToken == null) {
+                Slog.e(TAG, "windowToken cannot be null.");
                 return InputBindResult.NULL;
             }
+            try {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+                        "IMMS.startInputOrWindowGainedFocus");
+                ImeTracing.getInstance().triggerManagerServiceDump(
+                        "InputMethodManagerService#startInputOrWindowGainedFocus");
+                final int callingUserId = UserHandle.getCallingUserId();
+                final int userId;
+                if (attribute != null && attribute.targetInputMethodUser != null
+                        && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
+                    mContext.enforceCallingPermission(
+                            Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                            "Using EditorInfo.targetInputMethodUser requires"
+                                    + " INTERACT_ACROSS_USERS_FULL.");
+                    userId = attribute.targetInputMethodUser.getIdentifier();
+                    if (!mUserManagerInternal.isUserRunning(userId)) {
+                        // There is a chance that we hit here because of race condition. Let's just
+                        // return an error code instead of crashing the caller process, which at
+                        // least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an
+                        // important process.
+                        Slog.e(TAG, "User #" + userId + " is not running.");
+                        return InputBindResult.INVALID_USER;
+                    }
+                } else {
+                    userId = callingUserId;
+                }
+                final InputBindResult result;
+                synchronized (mMethodMap) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
+                                client, windowToken, startInputFlags, softInputMode, windowFlags,
+                                attribute, inputContext, missingMethods, unverifiedTargetSdkVersion,
+                                userId);
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
+                if (result == null) {
+                    // This must never happen, but just in case.
+                    Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+                            + InputMethodDebug.startInputReasonToString(startInputReason)
+                            + " windowFlags=#" + Integer.toHexString(windowFlags)
+                            + " editorInfo=" + attribute);
+                    return InputBindResult.NULL;
+                }
 
-            return result;
-        } finally {
-            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-        }
+                return result;
+            } finally {
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+            }
+        });
     }
 
     @NonNull
@@ -4076,6 +4124,44 @@
         return ImeTracing.getInstance().isEnabled();
     }
 
+    @BinderThread
+    @Override
+    public void startImeTrace() {
+        ImeTracing.getInstance().startTrace(null /* printwriter */);
+        ArrayMap<IBinder, ClientState> clients;
+        synchronized (mMethodMap) {
+            clients = new ArrayMap<>(mClients);
+        }
+        for (ClientState state : clients.values()) {
+            if (state != null) {
+                try {
+                    state.client.setImeTraceEnabled(true /* enabled */);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error while trying to enable ime trace on client window", e);
+                }
+            }
+        }
+    }
+
+    @BinderThread
+    @Override
+    public void stopImeTrace() {
+        ImeTracing.getInstance().stopTrace(null /* printwriter */);
+        ArrayMap<IBinder, ClientState> clients;
+        synchronized (mMethodMap) {
+            clients = new ArrayMap<>(mClients);
+        }
+        for (ClientState state : clients.values()) {
+            if (state != null) {
+                try {
+                    state.client.setImeTraceEnabled(false /* enabled */);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error while trying to disable ime trace on client window", e);
+                }
+            }
+        }
+    }
+
     @GuardedBy("mMethodMap")
     private void dumpDebug(ProtoOutputStream proto, long fieldId) {
         synchronized (mMethodMap) {
@@ -4451,15 +4537,20 @@
                 args.recycle();
                 return true;
             }
-            case MSG_SET_ACTIVE:
+            case MSG_SET_ACTIVE: {
+                args = (SomeArgs) msg.obj;
+                final ClientState clientState = (ClientState) args.arg1;
                 try {
-                    ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
+                    clientState.client.setActive(args.argi1 != 0 /* active */,
+                            args.argi2 != 0 /* fullScreen */,
+                            args.argi3 != 0 /* reportToImeController */);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
-                            + ((ClientState)msg.obj).pid + " uid "
-                            + ((ClientState)msg.obj).uid);
+                            + clientState.pid + " uid " + clientState.uid);
                 }
+                args.recycle();
                 return true;
+            }
             case MSG_SET_INTERACTIVE:
                 handleSetInteractive(msg.arg1 != 0);
                 return true;
@@ -4545,13 +4636,24 @@
 
             // Inform the current client of the change in active status
             if (mCurClient != null && mCurClient.client != null) {
-                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
-                        MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
-                        mCurClient));
+                boolean reportToImeController = false;
+                try {
+                    reportToImeController = mPlatformCompat.isChangeEnabledByUid(
+                            FINISH_INPUT_NO_FALLBACK_CONNECTION, mCurMethodUid);
+                } catch (RemoteException e) {
+                }
+                scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode,
+                        reportToImeController);
             }
         }
     }
 
+    private void scheduleSetActiveToClient(ClientState state, boolean active, boolean fullscreen,
+            boolean reportToImeController) {
+        executeOrSendMessage(state.client, mCaller.obtainMessageIIIIO(MSG_SET_ACTIVE,
+                active ? 1 : 0, fullscreen ? 1 : 0, reportToImeController ? 1 : 0, 0, state));
+    }
+
     private boolean chooseNewDefaultIMELocked() {
         final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
                 mSettings.getEnabledInputMethodListLocked());
@@ -5180,6 +5282,7 @@
             p.println("  mInFullscreenMode=" + mInFullscreenMode);
             p.println("  mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
             p.println("  mSettingsObserver=" + mSettingsObserver);
+            p.println("  mImeHiddenByDisplayPolicy=" + mImeHiddenByDisplayPolicy);
             p.println("  mSwitchingController:");
             mSwitchingController.dump(p);
             p.println("  mSettings:");
@@ -5322,20 +5425,7 @@
                     case "reset":
                         return mService.handleShellCommandResetInputMethod(this);
                     case "tracing":
-                        int result = ImeTracing.getInstance().onShellCommand(this);
-                        boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
-                        for (ClientState state : mService.mClients.values()) {
-                            if (state != null) {
-                                try {
-                                    state.client.setImeTraceEnabled(isImeTraceEnabled);
-                                } catch (RemoteException e) {
-                                    Log.e(TAG,
-                                            "Error while trying to enable/disable ime "
-                                                    + "trace on client window", e);
-                                }
-                            }
-                        }
-                        return result;
+                        return mService.handleShellCommandTraceInputMethod(this);
                     default:
                         getOutPrintWriter().println("Unknown command: " + imeCommand);
                         return ShellCommandResult.FAILURE;
@@ -5716,6 +5806,33 @@
     }
 
     /**
+     * Handles {@code adb shell ime tracing start/stop}.
+     * @param shellCommand {@link ShellCommand} object that is handling this command.
+     * @return Exit code of the command.
+     */
+    @BinderThread
+    @ShellCommandResult
+    private int handleShellCommandTraceInputMethod(@NonNull ShellCommand shellCommand) {
+        int result = ImeTracing.getInstance().onShellCommand(shellCommand);
+        boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
+        ArrayMap<IBinder, ClientState> clients;
+        synchronized (mMethodMap) {
+            clients = new ArrayMap<>(mClients);
+        }
+        for (ClientState state : clients.values()) {
+            if (state != null) {
+                try {
+                    state.client.setImeTraceEnabled(isImeTraceEnabled);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error while trying to enable/disable ime trace on client window",
+                            e);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
      * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
      * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
      * @return {@code true} if userId has debugging privileges.
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 7af27ca..6bdae63 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -72,6 +72,8 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.inputmethod.CallbackUtils;
+import com.android.internal.inputmethod.IInputBindResultResultCallback;
 import com.android.internal.inputmethod.IMultiClientInputMethod;
 import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.IMultiClientInputMethodSession;
@@ -104,6 +106,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.WeakHashMap;
+import java.util.function.Supplier;
 
 /**
  * Actual implementation of multi-client InputMethodManagerService.
@@ -911,7 +914,8 @@
                                     com.android.internal.R.string.input_method_binding_label)
                             .putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                                     context, 0,
-                                    new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
+                                    new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
+                                    PendingIntent.FLAG_MUTABLE));
 
             // Note: Instead of re-dispatching callback from the main thread to the worker thread
             // where OnWorkerThreadCallback is running, we pass the Handler object here so that
@@ -1338,7 +1342,7 @@
                 switch (clientInfo.mState) {
                     case InputMethodClientState.WAITING_FOR_IME_SESSION:
                         try {
-                            clientInfo.mClient.setActive(true, false);
+                            clientInfo.mClient.setActive(true, false, false);
                         } catch (RemoteException e) {
                             // TODO(yukawa): Remove this client.
                             return;
@@ -1400,7 +1404,7 @@
                     return;
                 }
                 try {
-                    clientInfo.mClient.setActive(active, false /* fullscreen */);
+                    clientInfo.mClient.setActive(active, false /* fullscreen */, false);
                 } catch (RemoteException e) {
                     return;
                 }
@@ -1587,7 +1591,26 @@
 
         @BinderThread
         @Override
-        public InputBindResult startInputOrWindowGainedFocus(
+        public void startInputOrWindowGainedFocus(
+                @StartInputReason int startInputReason,
+                @Nullable IInputMethodClient client,
+                @Nullable IBinder windowToken,
+                @StartInputFlags int startInputFlags,
+                @SoftInputModeFlags int softInputMode,
+                int windowFlags,
+                @Nullable EditorInfo editorInfo,
+                @Nullable IInputContext inputContext,
+                @MissingMethodFlags int missingMethods,
+                int unverifiedTargetSdkVersion,
+                IInputBindResultResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () ->
+                    startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
+                            startInputFlags, softInputMode, windowFlags, editorInfo, inputContext,
+                            missingMethods, unverifiedTargetSdkVersion));
+        }
+
+        @BinderThread
+        private InputBindResult startInputOrWindowGainedFocusInternal(
                 @StartInputReason int startInputReason,
                 @Nullable IInputMethodClient client,
                 @Nullable IBinder windowToken,
@@ -1675,8 +1698,7 @@
                                 clientInfo.mMSInputMethodSession.startInputOrWindowGainedFocus(
                                         inputContext, missingMethods, editorInfo, startInputFlags,
                                         softInputMode, windowHandle);
-                            } catch (RemoteException e) {
-                            }
+                            } catch (RemoteException ignored) { }
                             break;
                     }
                     return InputBindResult.NULL_EDITOR_INFO;
@@ -1707,8 +1729,7 @@
                             clientInfo.mMSInputMethodSession.startInputOrWindowGainedFocus(
                                     inputContext, missingMethods, editorInfo, startInputFlags,
                                     softInputMode, windowHandle);
-                        } catch (RemoteException e) {
-                        }
+                        } catch (RemoteException ignored) { }
                         clientInfo.mState = InputMethodClientState.ALREADY_SENT_BIND_RESULT;
                         return new InputBindResult(
                                 InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
@@ -1816,5 +1837,15 @@
         public boolean isImeTraceEnabled() {
             return false;
         }
+
+        @BinderThread
+        @Override
+        public void startImeTrace() {
+        }
+
+        @BinderThread
+        @Override
+        public void stopImeTrace() {
+        }
     }
 }
diff --git a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
index 28d2e69..ab91290 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
@@ -17,6 +17,7 @@
 package com.android.server.integrity.parser;
 
 import android.annotation.Nullable;
+import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
 import com.android.server.integrity.model.RuleMetadata;
@@ -26,7 +27,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 
 /** Helper class for parsing rule metadata. */
 public class RuleMetadataParser {
@@ -42,8 +42,7 @@
         String ruleProvider = "";
         String version = "";
 
-        XmlPullParser xmlPullParser = Xml.newPullParser();
-        xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
+        TypedXmlPullParser xmlPullParser = Xml.resolvePullParser(inputStream);
 
         int eventType;
         while ((eventType = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) {
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
index 5c51f31..7aed352 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
@@ -19,6 +19,7 @@
 import static com.android.server.integrity.parser.RuleMetadataParser.RULE_PROVIDER_TAG;
 import static com.android.server.integrity.parser.RuleMetadataParser.VERSION_TAG;
 
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.server.integrity.model.RuleMetadata;
@@ -34,8 +35,7 @@
     /** Serialize the rule metadata to an output stream. */
     public static void serialize(RuleMetadata ruleMetadata, OutputStream outputStream)
             throws IOException {
-        XmlSerializer xmlSerializer = Xml.newSerializer();
-        xmlSerializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
+        TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(outputStream);
 
         serializeTaggedValue(xmlSerializer, RULE_PROVIDER_TAG, ruleMetadata.getRuleProvider());
         serializeTaggedValue(xmlSerializer, VERSION_TAG, ruleMetadata.getVersion());
@@ -43,8 +43,8 @@
         xmlSerializer.endDocument();
     }
 
-    private static void serializeTaggedValue(XmlSerializer xmlSerializer, String tag, String value)
-            throws IOException {
+    private static void serializeTaggedValue(TypedXmlSerializer xmlSerializer, String tag,
+            String value) throws IOException {
         xmlSerializer.startTag(/* namespace= */ null, tag);
         xmlSerializer.text(value);
         xmlSerializer.endTag(/* namespace= */ null, tag);
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index a8889fd..9e12667 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -987,21 +987,17 @@
             // update client uids
             updateClientUids(mProviderRequest.getWorkSource());
 
-            mFixInterval = (int) mProviderRequest.getIntervalMillis();
-            // check for overflow
-            if (mFixInterval != mProviderRequest.getIntervalMillis()) {
+            if (mProviderRequest.getIntervalMillis() <= Integer.MAX_VALUE) {
+                mFixInterval = (int) mProviderRequest.getIntervalMillis();
+            } else {
                 Log.w(TAG, "interval overflow: " + mProviderRequest.getIntervalMillis());
                 mFixInterval = Integer.MAX_VALUE;
             }
-            // requested batch size, or zero to disable batching
-            int batchSize;
-            try {
-                batchSize = mBatchingEnabled ? Math.toIntExact(
-                        mProviderRequest.getMaxUpdateDelayMillis() / mFixInterval) : 0;
-            } catch (ArithmeticException e) {
-                batchSize = Integer.MAX_VALUE;
-            }
 
+            // requested batch size, or zero to disable batching
+            long batchSize =
+                    mBatchingEnabled ? mProviderRequest.getMaxUpdateDelayMillis() / Math.max(
+                            mFixInterval, 1) : 0;
             if (batchSize < getBatchSize()) {
                 batchSize = 0;
             }
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index 280d59af..b4bcd7b 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -25,10 +25,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
 import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
 
 import java.time.Duration;
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 70c1aef..07615ff 100644
--- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java
+++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
@@ -16,10 +16,9 @@
 
 package com.android.server.location.timezone;
 
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
-
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
 import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
 import static com.android.server.location.timezone.LocationTimeZoneManagerService.warnLog;
 import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState;
@@ -31,10 +30,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
 import com.android.server.location.timezone.ThreadingDomain.SingleRunnableQueue;
 import com.android.server.timezonedetector.ConfigurationInternal;
 import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index 83f4ca2..b7c7476 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -42,7 +42,7 @@
  * A service class that acts as a container for the {@link LocationTimeZoneProviderController},
  * which determines what {@link com.android.server.timezonedetector.GeolocationTimeZoneSuggestion}
  * are made to the {@link TimeZoneDetectorInternal}, and the {@link LocationTimeZoneProvider}s that
- * offer {@link android.location.timezone.LocationTimeZoneEvent}s.
+ * (indirectly) generate {@link com.android.internal.location.timezone.LocationTimeZoneEvent}s.
  *
  * <p>For details of the time zone suggestion behavior, see {@link
  * LocationTimeZoneProviderController}.
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
index 4bbda43..dc56238 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
@@ -16,10 +16,9 @@
 
 package com.android.server.location.timezone;
 
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
-
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
 import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
 import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
 import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
@@ -30,12 +29,12 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.os.Handler;
 import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
 import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
 import com.android.server.location.timezone.ThreadingDomain.SingleRunnableQueue;
 import com.android.server.timezonedetector.ConfigurationInternal;
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
index 3d889ae..1b4706f 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
@@ -19,11 +19,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.os.Handler;
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
 import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
 import com.android.server.timezonedetector.Dumpable;
 
diff --git a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
index 2bbae56..fbcc71f 100644
--- a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
@@ -38,8 +38,8 @@
  * enters a {@link ProviderState#PROVIDER_STATE_PERM_FAILED} state immediately after being enabled
  * for the first time and sends the appropriate event, which ensures the {@link
  * LocationTimeZoneProviderController} won't expect any further {@link
- * android.location.timezone.LocationTimeZoneEvent}s to come from it, and won't attempt to use it
- * again.
+ * com.android.internal.location.timezone.LocationTimeZoneEvent}s to come from it, and won't attempt
+ * to use it again.
  */
 class NullLocationTimeZoneProvider extends LocationTimeZoneProvider {
 
diff --git a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
index 94062fa..cd6d359 100644
--- a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.IndentingPrintWriter;
@@ -28,6 +27,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.location.timezone.ILocationTimeZoneProvider;
 import com.android.internal.location.timezone.ILocationTimeZoneProviderManager;
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
 import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
 import com.android.server.ServiceWatcher;
 
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
index 6bf6539..7725309 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
@@ -16,19 +16,19 @@
 
 package com.android.server.location.timezone;
 
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
-
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
 import static com.android.server.location.timezone.LocationTimeZoneManagerService.PRIMARY_PROVIDER_NAME;
 import static com.android.server.location.timezone.LocationTimeZoneManagerService.SECONDARY_PROVIDER_NAME;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.os.ShellCommand;
 import android.os.SystemClock;
 
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -117,7 +117,7 @@
 
     private static LocationTimeZoneEvent parseLocationTimeZoneEventArgs(ShellCommand shellCommand) {
         LocationTimeZoneEvent.Builder eventBuilder = new LocationTimeZoneEvent.Builder()
-                .setElapsedRealtimeNanos(SystemClock.elapsedRealtime());
+                .setElapsedRealtimeMillis(SystemClock.elapsedRealtime());
 
         String eventTypeString = shellCommand.getNextArgRequired();
         switch (eventTypeString.toUpperCase()) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
index 8a19d62..0c209c5 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
@@ -18,7 +18,6 @@
 
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERTIFICATE_FACTORY_TYPE;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE;
-import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
@@ -46,6 +45,7 @@
 import android.security.keystore.recovery.KeyDerivationParams;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.util.Base64;
+import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -84,8 +84,7 @@
 
     private static KeyChainSnapshot deserializeInternal(InputStream inputStream) throws IOException,
             XmlPullParserException, KeyChainSnapshotParserException {
-        XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(inputStream, OUTPUT_ENCODING);
+        TypedXmlPullParser parser = Xml.resolvePullParser(inputStream);
 
         parser.nextTag();
         parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
@@ -156,7 +155,7 @@
         }
     }
 
-    private static List<WrappedApplicationKey> readWrappedApplicationKeys(XmlPullParser parser)
+    private static List<WrappedApplicationKey> readWrappedApplicationKeys(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEYS);
         ArrayList<WrappedApplicationKey> keys = new ArrayList<>();
@@ -170,7 +169,7 @@
         return keys;
     }
 
-    private static WrappedApplicationKey readWrappedApplicationKey(XmlPullParser parser)
+    private static WrappedApplicationKey readWrappedApplicationKey(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEY);
         WrappedApplicationKey.Builder builder = new WrappedApplicationKey.Builder();
@@ -209,7 +208,7 @@
     }
 
     private static List<KeyChainProtectionParams> readKeyChainProtectionParamsList(
-            XmlPullParser parser) throws IOException, XmlPullParserException,
+            TypedXmlPullParser parser) throws IOException, XmlPullParserException,
             KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
 
@@ -225,7 +224,7 @@
         return keyChainProtectionParamsList;
     }
 
-    private static KeyChainProtectionParams readKeyChainProtectionParams(XmlPullParser parser)
+    private static KeyChainProtectionParams readKeyChainProtectionParams(TypedXmlPullParser parser)
         throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
 
@@ -269,7 +268,7 @@
         }
     }
 
-    private static KeyDerivationParams readKeyDerivationParams(XmlPullParser parser)
+    private static KeyDerivationParams readKeyDerivationParams(TypedXmlPullParser parser)
             throws XmlPullParserException, IOException, KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
 
@@ -331,7 +330,7 @@
         return keyDerivationParams;
     }
 
-    private static int readIntTag(XmlPullParser parser, String tagName)
+    private static int readIntTag(TypedXmlPullParser parser, String tagName)
             throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
         String text = readText(parser);
@@ -345,7 +344,7 @@
         }
     }
 
-    private static long readLongTag(XmlPullParser parser, String tagName)
+    private static long readLongTag(TypedXmlPullParser parser, String tagName)
             throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
         String text = readText(parser);
@@ -359,7 +358,7 @@
         }
     }
 
-    private static String readStringTag(XmlPullParser parser, String tagName)
+    private static String readStringTag(TypedXmlPullParser parser, String tagName)
             throws IOException, XmlPullParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
         String text = readText(parser);
@@ -367,7 +366,7 @@
         return text;
     }
 
-    private static byte[] readBlobTag(XmlPullParser parser, String tagName)
+    private static byte[] readBlobTag(TypedXmlPullParser parser, String tagName)
             throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
         parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
         String text = readText(parser);
@@ -384,7 +383,7 @@
         }
     }
 
-    private static CertPath readCertPathTag(XmlPullParser parser, String tagName)
+    private static CertPath readCertPathTag(TypedXmlPullParser parser, String tagName)
             throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
         byte[] bytes = readBlobTag(parser, tagName);
         try {
@@ -396,7 +395,7 @@
         }
     }
 
-    private static String readText(XmlPullParser parser)
+    private static String readText(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         String result = "";
         if (parser.next() == XmlPullParser.TEXT) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
index 8f85a27..6475d9e 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
@@ -22,8 +22,6 @@
 class KeyChainSnapshotSchema {
     static final String NAMESPACE = null;
 
-    static final String OUTPUT_ENCODING = "UTF-8";
-
     static final String CERTIFICATE_FACTORY_TYPE = "X.509";
     static final String CERT_PATH_ENCODING = "PkiPath";
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
index 527e879..eb34e98 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
@@ -19,7 +19,6 @@
 
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERT_PATH_ENCODING;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE;
-import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
@@ -47,10 +46,9 @@
 import android.security.keystore.recovery.KeyDerivationParams;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.util.Base64;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
-import org.xmlpull.v1.XmlSerializer;
-
 import java.io.IOException;
 import java.io.OutputStream;
 import java.security.cert.CertPath;
@@ -71,8 +69,7 @@
      */
     public static void serialize(KeyChainSnapshot keyChainSnapshot, OutputStream outputStream)
             throws IOException, CertificateEncodingException {
-        XmlSerializer xmlSerializer = Xml.newSerializer();
-        xmlSerializer.setOutput(outputStream, OUTPUT_ENCODING);
+        TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(outputStream);
         xmlSerializer.startDocument(
                 /*encoding=*/ null,
                 /*standalone=*/ null);
@@ -87,7 +84,7 @@
     }
 
     private static void writeApplicationKeys(
-            XmlSerializer xmlSerializer, List<WrappedApplicationKey> wrappedApplicationKeys)
+            TypedXmlSerializer xmlSerializer, List<WrappedApplicationKey> wrappedApplicationKeys)
             throws IOException {
         xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEYS);
         for (WrappedApplicationKey key : wrappedApplicationKeys) {
@@ -98,15 +95,15 @@
         xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEYS);
     }
 
-    private static void writeApplicationKeyProperties(
-            XmlSerializer xmlSerializer, WrappedApplicationKey applicationKey) throws IOException {
+    private static void writeApplicationKeyProperties(TypedXmlSerializer xmlSerializer,
+            WrappedApplicationKey applicationKey) throws IOException {
         writePropertyTag(xmlSerializer, TAG_ALIAS, applicationKey.getAlias());
         writePropertyTag(xmlSerializer, TAG_KEY_MATERIAL, applicationKey.getEncryptedKeyMaterial());
         writePropertyTag(xmlSerializer, TAG_KEY_METADATA, applicationKey.getMetadata());
     }
 
     private static void writeKeyChainProtectionParams(
-            XmlSerializer xmlSerializer,
+            TypedXmlSerializer xmlSerializer,
             List<KeyChainProtectionParams> keyChainProtectionParamsList) throws IOException {
         xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
         for (KeyChainProtectionParams keyChainProtectionParams : keyChainProtectionParamsList) {
@@ -118,7 +115,7 @@
     }
 
     private static void writeKeyChainProtectionParamsProperties(
-            XmlSerializer xmlSerializer, KeyChainProtectionParams keyChainProtectionParams)
+            TypedXmlSerializer xmlSerializer, KeyChainProtectionParams keyChainProtectionParams)
             throws IOException {
         writePropertyTag(xmlSerializer, TAG_USER_SECRET_TYPE,
                 keyChainProtectionParams.getUserSecretType());
@@ -132,7 +129,7 @@
     }
 
     private static void writeKeyDerivationParams(
-            XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
+            TypedXmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
             throws IOException {
         xmlSerializer.startTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
         writeKeyDerivationParamsProperties(
@@ -141,7 +138,7 @@
     }
 
     private static void writeKeyDerivationParamsProperties(
-            XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
+            TypedXmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
             throws IOException {
         writePropertyTag(xmlSerializer, TAG_ALGORITHM, keyDerivationParams.getAlgorithm());
         writePropertyTag(xmlSerializer, TAG_SALT, keyDerivationParams.getSalt());
@@ -150,7 +147,7 @@
     }
 
     private static void writeKeyChainSnapshotProperties(
-            XmlSerializer xmlSerializer, KeyChainSnapshot keyChainSnapshot)
+            TypedXmlSerializer xmlSerializer, KeyChainSnapshot keyChainSnapshot)
             throws IOException, CertificateEncodingException {
 
         writePropertyTag(xmlSerializer, TAG_SNAPSHOT_VERSION,
@@ -165,7 +162,7 @@
     }
 
     private static void writePropertyTag(
-            XmlSerializer xmlSerializer, String propertyName, long propertyValue)
+            TypedXmlSerializer xmlSerializer, String propertyName, long propertyValue)
             throws IOException {
         xmlSerializer.startTag(NAMESPACE, propertyName);
         xmlSerializer.text(Long.toString(propertyValue));
@@ -173,7 +170,7 @@
     }
 
     private static void writePropertyTag(
-            XmlSerializer xmlSerializer, String propertyName, String propertyValue)
+            TypedXmlSerializer xmlSerializer, String propertyName, String propertyValue)
             throws IOException {
         xmlSerializer.startTag(NAMESPACE, propertyName);
         xmlSerializer.text(propertyValue);
@@ -181,7 +178,7 @@
     }
 
     private static void writePropertyTag(
-            XmlSerializer xmlSerializer, String propertyName, @Nullable byte[] propertyValue)
+            TypedXmlSerializer xmlSerializer, String propertyName, @Nullable byte[] propertyValue)
             throws IOException {
         if (propertyValue == null) {
             return;
@@ -192,7 +189,7 @@
     }
 
     private static void writePropertyTag(
-            XmlSerializer xmlSerializer, String propertyName, CertPath certPath)
+            TypedXmlSerializer xmlSerializer, String propertyName, CertPath certPath)
             throws IOException, CertificateEncodingException {
         writePropertyTag(xmlSerializer, propertyName, certPath.getEncoded(CERT_PATH_ENCODING));
     }
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
index 0dbc839..63618ee 100644
--- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
+import android.content.Context;
 import android.media.session.ISessionManager;
 import android.media.session.MediaSession;
 import android.os.Binder;
@@ -60,7 +61,7 @@
 
     private Map<Integer, Integer> mOverriddenKeyEvents;
 
-    public MediaKeyDispatcher() {
+    public MediaKeyDispatcher(Context context) {
         // Constructor used for reflection
         mOverriddenKeyEvents = new HashMap<>();
         mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PLAY, 0);
diff --git a/services/core/java/com/android/server/media/MediaServerUtils.java b/services/core/java/com/android/server/media/MediaServerUtils.java
index 5fa2b1c..a4f11b2 100644
--- a/services/core/java/com/android/server/media/MediaServerUtils.java
+++ b/services/core/java/com/android/server/media/MediaServerUtils.java
@@ -18,6 +18,9 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
 import android.os.Binder;
 
 import java.io.PrintWriter;
@@ -29,7 +32,7 @@
     /**
      * Verify that caller holds {@link android.Manifest.permission#DUMP}.
      */
-    public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+    static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
         if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
             pw.println("Permission Denial: can't dump " + tag + " from from pid="
@@ -40,4 +43,18 @@
             return true;
         }
     }
+
+    /**
+     * Whether the given stream is currently active or not.
+     */
+    static boolean isStreamActive(AudioManager audioManager, int stream) {
+        for (AudioPlaybackConfiguration configuration
+                : audioManager.getActivePlaybackConfigurations()) {
+            AudioAttributes attributes = configuration.getAudioAttributes();
+            if (attributes != null && attributes.getVolumeControlStream() == stream) {
+                return configuration.isActive();
+            }
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index f997352..ea6e7d7 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -23,7 +23,6 @@
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
-import android.media.AudioSystem;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
@@ -513,7 +512,7 @@
             public void run() {
                 try {
                     if (useSuggested) {
-                        if (AudioSystem.isStreamActive(stream, 0)) {
+                        if (MediaServerUtils.isStreamActive(mAudioManager, stream)) {
                             mAudioManager.adjustSuggestedStreamVolumeForUid(stream,
                                     direction, flags, opPackageName, uid, pid,
                                     mContext.getApplicationInfo().targetSdkVersion);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index c23bfc4..11dbef2 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -43,7 +43,6 @@
 import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.media.AudioPlaybackConfiguration;
-import android.media.AudioSystem;
 import android.media.IRemoteVolumeControllerCallback;
 import android.media.Session2Token;
 import android.media.session.IActiveSessionsListener;
@@ -94,7 +93,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * System implementation of MediaSessionManager
@@ -149,7 +147,6 @@
 
     private SessionPolicyProvider mCustomSessionPolicyProvider;
     private MediaKeyDispatcher mCustomMediaKeyDispatcher;
-    private Map<Integer, Integer> mOverriddenKeyEventsMap;
 
     public MediaSessionService(Context context) {
         super(context);
@@ -780,7 +777,6 @@
     private void instantiateCustomDispatcher(String nameFromTesting) {
         synchronized (mLock) {
             mCustomMediaKeyDispatcher = null;
-            mOverriddenKeyEventsMap = null;
 
             String customDispatcherClassName = (nameFromTesting == null)
                     ? mContext.getResources().getString(R.string.config_customMediaKeyDispatcher)
@@ -788,9 +784,10 @@
             try {
                 if (!TextUtils.isEmpty(customDispatcherClassName)) {
                     Class customDispatcherClass = Class.forName(customDispatcherClassName);
-                    Constructor constructor = customDispatcherClass.getDeclaredConstructor();
-                    mCustomMediaKeyDispatcher = (MediaKeyDispatcher) constructor.newInstance();
-                    mOverriddenKeyEventsMap = mCustomMediaKeyDispatcher.getOverriddenKeyEvents();
+                    Constructor constructor =
+                            customDispatcherClass.getDeclaredConstructor(Context.class);
+                    mCustomMediaKeyDispatcher =
+                            (MediaKeyDispatcher) constructor.newInstance(mContext);
                 }
             } catch (ClassNotFoundException | InstantiationException | InvocationTargetException
                     | IllegalAccessException | NoSuchMethodException e) {
@@ -810,9 +807,10 @@
             try {
                 if (!TextUtils.isEmpty(customProviderClassName)) {
                     Class customProviderClass = Class.forName(customProviderClassName);
-                    Constructor constructor = customProviderClass.getDeclaredConstructor();
+                    Constructor constructor =
+                            customProviderClass.getDeclaredConstructor(Context.class);
                     mCustomSessionPolicyProvider =
-                            (SessionPolicyProvider) constructor.newInstance();
+                            (SessionPolicyProvider) constructor.newInstance(mContext);
                 }
             } catch (ClassNotFoundException | InstantiationException | InvocationTargetException
                     | IllegalAccessException | NoSuchMethodException e) {
@@ -2019,7 +2017,7 @@
 
             boolean preferSuggestedStream = false;
             if (isValidLocalStreamType(suggestedStream)
-                    && AudioSystem.isStreamActive(suggestedStream, 0)) {
+                    && MediaServerUtils.isStreamActive(mAudioManager, suggestedStream)) {
                 preferSuggestedStream = true;
             }
             if (session == null || preferSuggestedStream) {
@@ -2028,7 +2026,8 @@
                             + ". flags=" + flags + ", preferSuggestedStream="
                             + preferSuggestedStream + ", session=" + session);
                 }
-                if (musicOnly && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
+                if (musicOnly && !MediaServerUtils.isStreamActive(mAudioManager,
+                        AudioManager.STREAM_MUSIC)) {
                     if (DEBUG_KEY_EVENT) {
                         Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event,"
                                 + " flags=" + flags);
@@ -2382,9 +2381,12 @@
                     return;
                 }
 
-                int overriddenKeyEvents = (mCustomMediaKeyDispatcher == null) ? 0
-                        : mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
-                                .get(keyEvent.getKeyCode());
+                int overriddenKeyEvents = 0;
+                if (mCustomMediaKeyDispatcher != null
+                        && mCustomMediaKeyDispatcher.getOverriddenKeyEvents() != null) {
+                    overriddenKeyEvents = mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
+                            .get(keyEvent.getKeyCode());
+                }
                 cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent,
                         needWakeLock, opPackageName, stream, musicOnly, overriddenKeyEvents);
                 if (!needTracking(keyEvent, overriddenKeyEvents)) {
diff --git a/services/core/java/com/android/server/media/SessionPolicyProvider.java b/services/core/java/com/android/server/media/SessionPolicyProvider.java
index 5f02a07..332c85a 100644
--- a/services/core/java/com/android/server/media/SessionPolicyProvider.java
+++ b/services/core/java/com/android/server/media/SessionPolicyProvider.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.content.Context;
 import android.media.session.MediaSession;
 
 import java.lang.annotation.Retention;
@@ -54,7 +55,7 @@
      */
     static final int SESSION_POLICY_IGNORE_BUTTON_SESSION = 1 << 1;
 
-    public SessionPolicyProvider() {
+    public SessionPolicyProvider(Context context) {
         // Constructor used for reflection
     }
 
diff --git a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
index adb9869..9c68349 100644
--- a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
@@ -19,13 +19,17 @@
 import android.content.Context;
 import android.media.metrics.IPlaybackMetricsManager;
 import android.media.metrics.PlaybackMetrics;
+import android.util.Base64;
 
 import com.android.server.SystemService;
 
+import java.security.SecureRandom;
+
 /**
  * System service manages playback metrics.
  */
 public final class PlaybackMetricsManagerService extends SystemService {
+    private final SecureRandom mSecureRandom;
 
     /**
      * Initializes the playback metrics manager service.
@@ -34,6 +38,7 @@
      */
     public PlaybackMetricsManagerService(Context context) {
         super(context);
+        mSecureRandom = new SecureRandom();
     }
 
     @Override
@@ -44,8 +49,16 @@
 
     private final class BinderService extends IPlaybackMetricsManager.Stub {
         @Override
-        public void reportPlaybackMetrics(PlaybackMetrics metrics, int userId) {
+        public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) {
             // TODO: log it to statsd
         }
+
+        @Override
+        public String getSessionId(int userId) {
+            byte[] byteId = new byte[16]; // 128 bits
+            mSecureRandom.nextBytes(byteId);
+            String id = Base64.encodeToString(byteId, Base64.DEFAULT);
+            return id;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index bdf0fb9..8200ca0 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -34,6 +34,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -110,7 +111,7 @@
     }
 
     @Override
-    void writeDefaults(XmlSerializer out) throws IOException {
+    void writeDefaults(TypedXmlSerializer out) throws IOException {
         synchronized (mDefaultsLock) {
             String defaults = String.join(ENABLED_SERVICES_SEPARATOR, mDefaultPackages);
             out.attribute(null, ATT_DEFAULTS, defaults);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index f2e3708..a7ee272 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -60,6 +60,8 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
@@ -443,7 +445,7 @@
         }
     }
 
-    void writeDefaults(XmlSerializer out) throws IOException {
+    void writeDefaults(TypedXmlSerializer out) throws IOException {
         synchronized (mDefaultsLock) {
             List<String> componentStrings = new ArrayList<>(mDefaultComponents.size());
             for (int i = 0; i < mDefaultComponents.size(); i++) {
@@ -454,10 +456,10 @@
         }
     }
 
-    public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
+    public void writeXml(TypedXmlSerializer out, boolean forBackup, int userId) throws IOException {
         out.startTag(null, getConfig().xmlTag);
 
-        out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
+        out.attributeInt(null, ATT_VERSION, DB_VERSION);
 
         writeDefaults(out);
 
@@ -485,8 +487,8 @@
                                     : String.join(ENABLED_SERVICES_SEPARATOR, approved);
                             out.startTag(null, TAG_MANAGED_SERVICES);
                             out.attribute(null, ATT_APPROVED_LIST, allowedItems);
-                            out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
-                            out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
+                            out.attributeInt(null, ATT_USER_ID, approvedUserId);
+                            out.attributeBoolean(null, ATT_IS_PRIMARY, isPrimary);
                             if (userSet != null) {
                                 String userSetItems =
                                         String.join(ENABLED_SERVICES_SEPARATOR, userSet);
@@ -516,23 +518,23 @@
     /**
      * Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
      */
-    protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
+    protected void writeExtraAttributes(TypedXmlSerializer out, int userId) throws IOException {}
 
     /**
      * Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
      */
-    protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
+    protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {}
 
     /**
      * This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
      */
-    protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
+    protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {}
 
     protected void migrateToXml() {
         loadAllowedComponentsFromSettings();
     }
 
-    void readDefaults(XmlPullParser parser) {
+    void readDefaults(TypedXmlPullParser parser) {
         String defaultComponents = XmlUtils.readStringAttribute(parser, ATT_DEFAULTS);
 
         if (!TextUtils.isEmpty(defaultComponents)) {
@@ -554,7 +556,7 @@
     }
 
     public void readXml(
-            XmlPullParser parser,
+            TypedXmlPullParser parser,
             TriPredicate<String, Integer, String> allowedManagedServicePackages,
             boolean forRestore,
             int userId)
@@ -577,9 +579,9 @@
                     final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
                     // Ignore parser's user id for restore.
                     final int resolvedUserId = forRestore
-                            ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
+                            ? userId : parser.getAttributeInt(null, ATT_USER_ID, 0);
                     final boolean isPrimary =
-                            XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
+                            parser.getAttributeBoolean(null, ATT_IS_PRIMARY, true);
                     final String userSet = XmlUtils.readStringAttribute(parser, ATT_USER_SET);
                     readExtraAttributes(tag, parser, resolvedUserId);
                     if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
@@ -631,7 +633,7 @@
     /**
      * Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
      */
-    protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
+    protected void readExtraAttributes(String tag, TypedXmlPullParser parser, int userId)
             throws IOException {}
 
     protected abstract String getRequiredPermission();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b1289dd..76b9c86 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -231,6 +231,8 @@
 import android.util.SparseArray;
 import android.util.StatsEvent;
 import android.util.Xml;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -743,8 +745,13 @@
 
     void readPolicyXml(InputStream stream, boolean forRestore, int userId)
             throws XmlPullParserException, NumberFormatException, IOException {
-        final XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(stream, StandardCharsets.UTF_8.name());
+        final TypedXmlPullParser parser;
+        if (forRestore) {
+            parser = Xml.newFastPullParser();
+            parser.setInput(stream, StandardCharsets.UTF_8.name());
+        } else {
+            parser = Xml.resolvePullParser(stream);
+        }
         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
         boolean migratedManagedServices = false;
         boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId);
@@ -781,9 +788,8 @@
                 if (forRestore && userId != UserHandle.USER_SYSTEM) {
                     continue;
                 }
-                mLockScreenAllowSecureNotifications =
-                        safeBoolean(parser.getAttributeValue(null,
-                                        LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
+                mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null,
+                        LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true);
             }
         }
 
@@ -856,11 +862,16 @@
 
     private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
             throws IOException {
-        final XmlSerializer out = new FastXmlSerializer();
-        out.setOutput(stream, StandardCharsets.UTF_8.name());
+        final TypedXmlSerializer out;
+        if (forBackup) {
+            out = Xml.newFastSerializer();
+            out.setOutput(stream, StandardCharsets.UTF_8.name());
+        } else {
+            out = Xml.resolveSerializer(stream);
+        }
         out.startDocument(null, true);
         out.startTag(null, TAG_NOTIFICATION_POLICY);
-        out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+        out.attributeInt(null, ATTR_VERSION, DB_VERSION);
         mZenModeHelper.writeXml(out, forBackup, null, userId);
         mPreferencesHelper.writeXml(out, forBackup, userId);
         mListeners.writeXml(out, forBackup, userId);
@@ -8975,7 +8986,7 @@
         }
 
         @Override
-        protected void writeExtraXmlTags(XmlSerializer out) throws IOException {
+        protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
             synchronized (mLock) {
                 out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
                 out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
@@ -8984,7 +8995,7 @@
         }
 
         @Override
-        protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {
+        protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {
             if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
                 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
                 synchronized (mLock) {
@@ -9104,9 +9115,9 @@
         }
 
         @Override
-        protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
+        protected void readExtraAttributes(String tag, TypedXmlPullParser parser, int userId)
                 throws IOException {
-            boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false);
+            boolean userSet = parser.getAttributeBoolean(null, ATT_USER_SET, false);
             setUserSet(userId, userSet);
         }
 
@@ -10106,18 +10117,13 @@
         }
     }
 
-    private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
+    private void writeSecureNotificationsPolicy(TypedXmlSerializer out) throws IOException {
         out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
-        out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
-                Boolean.toString(mLockScreenAllowSecureNotifications));
+        out.attributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
+                mLockScreenAllowSecureNotifications);
         out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
     }
 
-    private static boolean safeBoolean(String val, boolean defValue) {
-        if (TextUtils.isEmpty(val)) return defValue;
-        return Boolean.parseBoolean(val);
-    }
-
     /**
      * Shows a warning on logcat. Shows the toast only once per package. This is to avoid being too
      * aggressive and annoying the user.
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 2f990c6..1c0349d 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -56,6 +56,8 @@
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
@@ -195,21 +197,15 @@
         syncChannelsBypassingDnd(mContext.getUserId());
     }
 
-    public void readXml(XmlPullParser parser, boolean forRestore, int userId)
+    public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId)
             throws XmlPullParserException, IOException {
         int type = parser.getEventType();
         if (type != XmlPullParser.START_TAG) return;
         String tag = parser.getName();
         if (!TAG_RANKING.equals(tag)) return;
 
-        boolean upgradeForBubbles = false;
-        if (parser.getAttributeCount() > 0) {
-            String attribute = parser.getAttributeName(0);
-            if (ATT_VERSION.equals(attribute)) {
-                int xmlVersion = Integer.parseInt(parser.getAttributeValue(0));
-                upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE;
-            }
-        }
+        final int xmlVersion = parser.getAttributeInt(null, ATT_VERSION, -1);
+        boolean upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE;
         synchronized (mPackagePreferences) {
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 tag = parser.getName();
@@ -221,10 +217,10 @@
                         if (forRestore && userId != UserHandle.USER_SYSTEM) {
                             continue;
                         }
-                        mHideSilentStatusBarIcons = XmlUtils.readBooleanAttribute(
-                                parser, ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
+                        mHideSilentStatusBarIcons = parser.getAttributeBoolean(null,
+                                ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
                     } else if (TAG_PACKAGE.equals(tag)) {
-                        int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+                        int uid = parser.getAttributeInt(null, ATT_UID, UNKNOWN_UID);
                         String name = parser.getAttributeValue(null, ATT_NAME);
                         if (!TextUtils.isEmpty(name)) {
                             if (forRestore) {
@@ -243,36 +239,36 @@
                             }
                             int bubblePref = hasSAWPermission
                                     ? BUBBLE_PREFERENCE_ALL
-                                    : XmlUtils.readIntAttribute(parser, ATT_ALLOW_BUBBLE,
-                                            DEFAULT_BUBBLE_PREFERENCE);
+                                    : parser.getAttributeInt(
+                                            null, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE);
 
                             PackagePreferences r = getOrCreatePackagePreferencesLocked(
                                     name, userId, uid,
-                                    XmlUtils.readIntAttribute(
-                                            parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
-                                    XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
-                                            DEFAULT_PRIORITY),
-                                    XmlUtils.readIntAttribute(
-                                            parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
-                                    XmlUtils.readBooleanAttribute(
-                                            parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
+                                    parser.getAttributeInt(
+                                            null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
+                                    parser.getAttributeInt(
+                                            null, ATT_PRIORITY, DEFAULT_PRIORITY),
+                                    parser.getAttributeInt(
+                                            null, ATT_VISIBILITY, DEFAULT_VISIBILITY),
+                                    parser.getAttributeBoolean(
+                                            null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
                                     bubblePref);
-                            r.importance = XmlUtils.readIntAttribute(
-                                    parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
-                            r.priority = XmlUtils.readIntAttribute(
-                                    parser, ATT_PRIORITY, DEFAULT_PRIORITY);
-                            r.visibility = XmlUtils.readIntAttribute(
-                                    parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
-                            r.showBadge = XmlUtils.readBooleanAttribute(
-                                    parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
-                            r.lockedAppFields = XmlUtils.readIntAttribute(parser,
-                                    ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
-                            r.hasSentInvalidMessage = XmlUtils.readBooleanAttribute(
-                                    parser, ATT_SENT_INVALID_MESSAGE, false);
-                            r.hasSentValidMessage = XmlUtils.readBooleanAttribute(
-                                    parser, ATT_SENT_VALID_MESSAGE, false);
-                            r.userDemotedMsgApp = XmlUtils.readBooleanAttribute(
-                                    parser, ATT_USER_DEMOTED_INVALID_MSG_APP, false);
+                            r.importance = parser.getAttributeInt(
+                                    null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+                            r.priority = parser.getAttributeInt(
+                                    null, ATT_PRIORITY, DEFAULT_PRIORITY);
+                            r.visibility = parser.getAttributeInt(
+                                    null, ATT_VISIBILITY, DEFAULT_VISIBILITY);
+                            r.showBadge = parser.getAttributeBoolean(
+                                    null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
+                            r.lockedAppFields = parser.getAttributeInt(
+                                    null, ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
+                            r.hasSentInvalidMessage = parser.getAttributeBoolean(
+                                    null, ATT_SENT_INVALID_MESSAGE, false);
+                            r.hasSentValidMessage = parser.getAttributeBoolean(
+                                    null, ATT_SENT_VALID_MESSAGE, false);
+                            r.userDemotedMsgApp = parser.getAttributeBoolean(
+                                    null, ATT_USER_DEMOTED_INVALID_MSG_APP, false);
 
                             final int innerDepth = parser.getDepth();
                             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -307,8 +303,8 @@
                                     }
                                     String id = parser.getAttributeValue(null, ATT_ID);
                                     String channelName = parser.getAttributeValue(null, ATT_NAME);
-                                    int channelImportance = XmlUtils.readIntAttribute(
-                                            parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+                                    int channelImportance = parser.getAttributeInt(
+                                            null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                                     if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
                                         NotificationChannel channel = new NotificationChannel(id,
                                                 channelName, channelImportance);
@@ -338,14 +334,13 @@
                                 // Delegate
                                 if (TAG_DELEGATE.equals(tagName)) {
                                     int delegateId =
-                                            XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+                                            parser.getAttributeInt(null, ATT_UID, UNKNOWN_UID);
                                     String delegateName =
                                             XmlUtils.readStringAttribute(parser, ATT_NAME);
-                                    boolean delegateEnabled = XmlUtils.readBooleanAttribute(
-                                            parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
-                                    boolean userAllowed = XmlUtils.readBooleanAttribute(
-                                            parser, ATT_USER_ALLOWED,
-                                            Delegate.DEFAULT_USER_ALLOWED);
+                                    boolean delegateEnabled = parser.getAttributeBoolean(
+                                            null, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
+                                    boolean userAllowed = parser.getAttributeBoolean(
+                                            null, ATT_USER_ALLOWED, Delegate.DEFAULT_USER_ALLOWED);
                                     Delegate d = null;
                                     if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(
                                             delegateName)) {
@@ -502,13 +497,13 @@
         return true;
     }
 
-    public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
+    public void writeXml(TypedXmlSerializer out, boolean forBackup, int userId) throws IOException {
         out.startTag(null, TAG_RANKING);
-        out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
+        out.attributeInt(null, ATT_VERSION, XML_VERSION);
         if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS
                 && (!forBackup || userId == UserHandle.USER_SYSTEM)) {
             out.startTag(null, TAG_STATUS_ICONS);
-            out.attribute(null, ATT_HIDE_SILENT, String.valueOf(mHideSilentStatusBarIcons));
+            out.attributeBoolean(null, ATT_HIDE_SILENT, mHideSilentStatusBarIcons);
             out.endTag(null, TAG_STATUS_ICONS);
         }
 
@@ -536,42 +531,41 @@
                     out.startTag(null, TAG_PACKAGE);
                     out.attribute(null, ATT_NAME, r.pkg);
                     if (r.importance != DEFAULT_IMPORTANCE) {
-                        out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+                        out.attributeInt(null, ATT_IMPORTANCE, r.importance);
                     }
                     if (r.priority != DEFAULT_PRIORITY) {
-                        out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
+                        out.attributeInt(null, ATT_PRIORITY, r.priority);
                     }
                     if (r.visibility != DEFAULT_VISIBILITY) {
-                        out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
+                        out.attributeInt(null, ATT_VISIBILITY, r.visibility);
                     }
                     if (r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE) {
-                        out.attribute(null, ATT_ALLOW_BUBBLE, Integer.toString(r.bubblePreference));
+                        out.attributeInt(null, ATT_ALLOW_BUBBLE, r.bubblePreference);
                     }
-                    out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
-                    out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
-                            Integer.toString(r.lockedAppFields));
-                    out.attribute(null, ATT_SENT_INVALID_MESSAGE,
-                            Boolean.toString(r.hasSentInvalidMessage));
-                    out.attribute(null, ATT_SENT_VALID_MESSAGE,
-                            Boolean.toString(r.hasSentValidMessage));
-                    out.attribute(null, ATT_USER_DEMOTED_INVALID_MSG_APP,
-                            Boolean.toString(r.userDemotedMsgApp));
+                    out.attributeBoolean(null, ATT_SHOW_BADGE, r.showBadge);
+                    out.attributeInt(null, ATT_APP_USER_LOCKED_FIELDS,
+                            r.lockedAppFields);
+                    out.attributeBoolean(null, ATT_SENT_INVALID_MESSAGE,
+                            r.hasSentInvalidMessage);
+                    out.attributeBoolean(null, ATT_SENT_VALID_MESSAGE,
+                            r.hasSentValidMessage);
+                    out.attributeBoolean(null, ATT_USER_DEMOTED_INVALID_MSG_APP,
+                            r.userDemotedMsgApp);
 
                     if (!forBackup) {
-                        out.attribute(null, ATT_UID, Integer.toString(r.uid));
+                        out.attributeInt(null, ATT_UID, r.uid);
                     }
 
                     if (r.delegate != null) {
                         out.startTag(null, TAG_DELEGATE);
 
                         out.attribute(null, ATT_NAME, r.delegate.mPkg);
-                        out.attribute(null, ATT_UID, Integer.toString(r.delegate.mUid));
+                        out.attributeInt(null, ATT_UID, r.delegate.mUid);
                         if (r.delegate.mEnabled != Delegate.DEFAULT_ENABLED) {
-                            out.attribute(null, ATT_ENABLED, Boolean.toString(r.delegate.mEnabled));
+                            out.attributeBoolean(null, ATT_ENABLED, r.delegate.mEnabled);
                         }
                         if (r.delegate.mUserAllowed != Delegate.DEFAULT_USER_ALLOWED) {
-                            out.attribute(null, ATT_USER_ALLOWED,
-                                    Boolean.toString(r.delegate.mUserAllowed));
+                            out.attributeBoolean(null, ATT_USER_ALLOWED, r.delegate.mUserAllowed);
                         }
                         out.endTag(null, TAG_DELEGATE);
                     }
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index f7d69fd..b5ca2ab 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -32,6 +32,8 @@
 import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
@@ -57,7 +59,7 @@
  * NotificationManagerService helper for handling snoozed notifications.
  */
 public class SnoozeHelper {
-    public static final String XML_SNOOZED_NOTIFICATION_VERSION = "1";
+    public static final int XML_SNOOZED_NOTIFICATION_VERSION = 1;
 
     protected static final String XML_TAG_NAME = "snoozed-notifications";
 
@@ -547,7 +549,7 @@
         }
     }
 
-    protected void writeXml(XmlSerializer out) throws IOException {
+    protected void writeXml(TypedXmlSerializer out) throws IOException {
         synchronized (mLock) {
             final long currentTime = System.currentTimeMillis();
             out.startTag(null, XML_TAG_NAME);
@@ -573,7 +575,7 @@
         void insert(T t) throws IOException;
     }
 
-    private <T> void writeXml(XmlSerializer out,
+    private <T> void writeXml(TypedXmlSerializer out,
             ArrayMap<String, ArrayMap<String, T>> targets, String tag,
             Inserter<T> attributeInserter)
             throws IOException {
@@ -596,21 +598,18 @@
 
                 attributeInserter.insert(value);
 
-                out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
+                out.attributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
                         XML_SNOOZED_NOTIFICATION_VERSION);
                 out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
-
-
                 out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg);
-                out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
-                        String.valueOf(userId));
+                out.attributeInt(null, XML_SNOOZED_NOTIFICATION_USER_ID, userId);
 
                 out.endTag(null, tag);
             }
         }
     }
 
-    protected void readXml(XmlPullParser parser, long currentTime)
+    protected void readXml(TypedXmlPullParser parser, long currentTime)
             throws XmlPullParserException, IOException {
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -622,16 +621,16 @@
             if (type == XmlPullParser.START_TAG
                     && (XML_SNOOZED_NOTIFICATION.equals(tag)
                         || tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT))
-                    && parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL)
-                        .equals(XML_SNOOZED_NOTIFICATION_VERSION)) {
+                    && parser.getAttributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL, -1)
+                        == XML_SNOOZED_NOTIFICATION_VERSION) {
                 try {
                     final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY);
                     final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG);
-                    final int userId = XmlUtils.readIntAttribute(
-                            parser, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
+                    final int userId = parser.getAttributeInt(
+                            null, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
                     if (tag.equals(XML_SNOOZED_NOTIFICATION)) {
-                        final Long time = XmlUtils.readLongAttribute(
-                                parser, XML_SNOOZED_NOTIFICATION_TIME, 0);
+                        final Long time = parser.getAttributeLong(
+                                null, XML_SNOOZED_NOTIFICATION_TIME, 0);
                         if (time > currentTime) { //only read new stuff
                             synchronized (mLock) {
                                 storeRecordLocked(
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 13cd6e5..94f46ba 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -72,6 +72,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
@@ -702,7 +704,7 @@
         }
     }
 
-    public void readXml(XmlPullParser parser, boolean forRestore, int userId)
+    public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId)
             throws XmlPullParserException, IOException {
         ZenModeConfig config = ZenModeConfig.readXml(parser);
         String reason = "readXml";
@@ -761,7 +763,7 @@
         }
     }
 
-    public void writeXml(XmlSerializer out, boolean forBackup, Integer version, int userId)
+    public void writeXml(TypedXmlSerializer out, boolean forBackup, Integer version, int userId)
             throws IOException {
         synchronized (mConfigs) {
             final int n = mConfigs.size();
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 8a2d823..0613dff 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -411,7 +411,7 @@
                 table.clear();
                 final TypedXmlPullParser parser = Xml.resolvePullParser(is);
                 XmlUtils.beginDocument(parser, TAG_OVERLAYS);
-                int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION);
+                int version = parser.getAttributeInt(null, ATTR_VERSION);
                 if (version != CURRENT_VERSION) {
                     upgrade(version);
                 }
@@ -445,19 +445,19 @@
             }
         }
 
-        private static SettingsItem restoreRow(@NonNull final XmlPullParser parser, final int depth)
-                throws IOException {
+        private static SettingsItem restoreRow(@NonNull final TypedXmlPullParser parser,
+                final int depth) throws IOException, XmlPullParserException {
             final String packageName = XmlUtils.readStringAttribute(parser, ATTR_PACKAGE_NAME);
-            final int userId = XmlUtils.readIntAttribute(parser, ATTR_USER_ID);
+            final int userId = parser.getAttributeInt(null, ATTR_USER_ID);
             final String targetPackageName = XmlUtils.readStringAttribute(parser,
                     ATTR_TARGET_PACKAGE_NAME);
             final String targetOverlayableName = XmlUtils.readStringAttribute(parser,
                     ATTR_TARGET_OVERLAYABLE_NAME);
             final String baseCodePath = XmlUtils.readStringAttribute(parser, ATTR_BASE_CODE_PATH);
-            final int state = XmlUtils.readIntAttribute(parser, ATTR_STATE);
-            final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED);
-            final boolean isStatic = XmlUtils.readBooleanAttribute(parser, ATTR_IS_STATIC);
-            final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY);
+            final int state = parser.getAttributeInt(null, ATTR_STATE);
+            final boolean isEnabled = parser.getAttributeBoolean(null, ATTR_IS_ENABLED, false);
+            final boolean isStatic = parser.getAttributeBoolean(null, ATTR_IS_STATIC, false);
+            final int priority = parser.getAttributeInt(null, ATTR_PRIORITY);
             final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY);
 
             return new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
@@ -470,7 +470,7 @@
             xml.startDocument(null, true);
             xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             xml.startTag(null, TAG_OVERLAYS);
-            XmlUtils.writeIntAttribute(xml, ATTR_VERSION, CURRENT_VERSION);
+            xml.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
 
             final int n = table.size();
             for (int i = 0; i < n; i++) {
@@ -485,15 +485,15 @@
                 @NonNull final SettingsItem item) throws IOException {
             xml.startTag(null, TAG_ITEM);
             XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.mPackageName);
-            XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.mUserId);
+            xml.attributeInt(null, ATTR_USER_ID, item.mUserId);
             XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.mTargetPackageName);
             XmlUtils.writeStringAttribute(xml, ATTR_TARGET_OVERLAYABLE_NAME,
                     item.mTargetOverlayableName);
             XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.mBaseCodePath);
-            XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.mState);
+            xml.attributeInt(null, ATTR_STATE, item.mState);
             XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled);
             XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, !item.mIsMutable);
-            XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority);
+            xml.attributeInt(null, ATTR_PRIORITY, item.mPriority);
             XmlUtils.writeStringAttribute(xml, ATTR_CATEGORY, item.mCategory);
             xml.endTag(null, TAG_ITEM);
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5c2c8e2..c10d394 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2544,6 +2544,10 @@
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Full install must include a base package");
             }
+            if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
+                throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
+                        "Missing split for " + mPackageName);
+            }
         } else {
             final ApplicationInfo appInfo = pkgInfo.applicationInfo;
             ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
@@ -2654,6 +2658,17 @@
                     mResolvedInheritedFiles.addAll(libFilesToInherit);
                 }
             }
+            // For the case of split required, failed if no splits existed
+            if (baseApk.isSplitRequired) {
+                final int existingSplits = ArrayUtils.size(existing.splitNames);
+                final boolean allSplitsRemoved = (existingSplits == removeSplitList.size());
+                final boolean onlyBaseFileStaged = (stagedSplits.size() == 1
+                        && stagedSplits.contains(null));
+                if (allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged)) {
+                    throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
+                            "Missing split for " + mPackageName);
+                }
+            }
         }
         if (baseApk.useEmbeddedDex) {
             for (File file : mResolvedStagedFiles) {
@@ -2665,10 +2680,6 @@
                 }
             }
         }
-        if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
-            throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
-                    "Missing split for " + mPackageName);
-        }
 
         final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
         if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3880711..85659ed 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21,7 +21,6 @@
 import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
-import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.content.Intent.ACTION_MAIN;
@@ -44,7 +43,6 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
@@ -141,6 +139,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.ActivityManager;
@@ -342,7 +341,6 @@
 import com.android.internal.content.om.OverlayConfig;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.os.Zygote;
 import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ConcurrentUtils;
@@ -1203,6 +1201,7 @@
         public ViewCompiler viewCompiler;
         public @Nullable String wellbeingPackage;
         public @Nullable String retailDemoPackage;
+        public @Nullable String recentsPackage;
         public ComponentName resolveComponentName;
         public ArrayMap<String, AndroidPackage> packages;
         public boolean enableFreeCacheV2;
@@ -1737,10 +1736,19 @@
     final @Nullable String mSharedSystemSharedLibraryPackageName;
     final @Nullable String mRetailDemoPackage;
     final @Nullable String mOverlayConfigSignaturePackage;
+    final @Nullable String mRecentsPackage;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
     private final CompilerStats mCompilerStats = new CompilerStats();
 
+    /**
+     * Invalidate the package info cache, which includes updating the cached computer.
+     * @hide
+     */
+    public static void invalidatePackageInfoCache() {
+        PackageManager.invalidatePackageInfoCache();
+    }
+
     class PackageHandler extends Handler {
 
         PackageHandler(Looper looper) {
@@ -2169,7 +2177,7 @@
 
     private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
             boolean killApp, boolean virtualPreload,
-            String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
+            String[] grantedPermissions, List<String> allowlistedRestrictedPermissions,
             int autoRevokePermissionsMode,
             boolean launchedForRestore, String installerPackage,
             IPackageInstallObserver2 installObserver, int dataLoaderType) {
@@ -2202,31 +2210,22 @@
                 res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
             }
 
-            // Allowlist any restricted permissions first as some may be runtime
-            // that the installer requested to be granted at install time.
-            if (whitelistedRestrictedPermissions != null
-                    && !whitelistedRestrictedPermissions.isEmpty()) {
-                mPermissionManager.setAllowlistedRestrictedPermissions(res.pkg,
-                        whitelistedRestrictedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER,
-                        res.newUsers);
-            }
-
-            if (autoRevokePermissionsMode == MODE_ALLOWED
-                    || autoRevokePermissionsMode == MODE_IGNORED) {
-                mPermissionManager.setAutoRevokeExempted(res.pkg,
-                        autoRevokePermissionsMode == MODE_IGNORED, res.newUsers);
-            }
-
-            // Now that we successfully installed the package, grant runtime
-            // permissions if requested before broadcasting the install. Also
-            // for legacy apps in permission review mode we clear the permission
-            // review flag which is used to emulate runtime permissions for
-            // legacy apps.
+            final List<String> grantedPermissionsList;
             if (grantPermissions) {
-                final int callingUid = Binder.getCallingUid();
-                mPermissionManager.grantRequestedRuntimePermissions(res.pkg,
-                        grantedPermissions != null ? Arrays.asList(grantedPermissions) : null,
-                        res.newUsers);
+                if (grantedPermissions != null) {
+                    grantedPermissionsList = Arrays.asList(grantedPermissions);
+                } else {
+                    grantedPermissionsList = res.pkg.getRequestedPermissions();
+                }
+            } else {
+                grantedPermissionsList = Collections.emptyList();
+            }
+            if (allowlistedRestrictedPermissions == null) {
+                allowlistedRestrictedPermissions = Collections.emptyList();
+            }
+            for (final int userId : res.newUsers) {
+                mPermissionManager.onPackageInstalled(res.pkg, grantedPermissionsList,
+                        allowlistedRestrictedPermissions, autoRevokePermissionsMode, userId);
             }
 
             final String installerPackageName =
@@ -2692,14 +2691,14 @@
         // We normally invalidate when we write settings, but in cases where we delay and
         // coalesce settings writes, this strategy would have us invalidate the cache too late.
         // Invalidating on schedule addresses this problem.
-        PackageManager.invalidatePackageInfoCache();
+        invalidatePackageInfoCache();
         if (!mHandler.hasMessages(WRITE_SETTINGS)) {
             mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
         }
     }
 
     void scheduleWritePackageListLocked(int userId) {
-        PackageManager.invalidatePackageInfoCache();
+        invalidatePackageInfoCache();
         if (!mHandler.hasMessages(WRITE_PACKAGE_LIST)) {
             Message msg = mHandler.obtainMessage(WRITE_PACKAGE_LIST);
             msg.arg1 = userId;
@@ -2713,7 +2712,7 @@
     }
 
     void scheduleWritePackageRestrictionsLocked(int userId) {
-        PackageManager.invalidatePackageInfoCache();
+        invalidatePackageInfoCache();
         final int[] userIds = (userId == UserHandle.USER_ALL)
                 ? mUserManager.getUserIds() : new int[]{userId};
         for (int nextUserId : userIds) {
@@ -2980,6 +2979,7 @@
         mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage;
         mWellbeingPackage = testParams.wellbeingPackage;
         mRetailDemoPackage = testParams.retailDemoPackage;
+        mRecentsPackage = testParams.recentsPackage;
         mDocumenterPackage = testParams.documenterPackage;
         mConfiguratorPackage = testParams.configuratorPackage;
         mAppPredictionServicePackage = testParams.appPredictionServicePackage;
@@ -3564,6 +3564,7 @@
             mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
             mRetailDemoPackage = getRetailDemoPackageName();
             mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
+            mRecentsPackage = getRecentsPackageName();
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
@@ -4100,10 +4101,7 @@
         // feature flags should cause us to invalidate any caches.
         final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
                 : injector.getSystemWrapper().digestOfProperties(
-                        "ro.build.fingerprint",
-                        StorageManager.PROP_ISOLATED_STORAGE,
-                        StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT
-                );
+                        "ro.build.fingerprint");
 
         // Reconcile cache directories, keeping only what we'd actually use.
         for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -5712,7 +5710,8 @@
                             getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
                             (libInfo.getDependencies() == null
                                     ? null
-                                    : new ArrayList<>(libInfo.getDependencies())));
+                                    : new ArrayList<>(libInfo.getDependencies())),
+                            libInfo.isNative());
 
                     if (result == null) {
                         result = new ArrayList<>();
@@ -5781,7 +5780,8 @@
                             libraryInfo.getLongVersion(), libraryInfo.getType(),
                             libraryInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(
                             libraryInfo, flags, userId), libraryInfo.getDependencies() == null
-                            ? null : new ArrayList<>(libraryInfo.getDependencies()));
+                            ? null : new ArrayList<>(libraryInfo.getDependencies()),
+                            libraryInfo.isNative());
 
                     if (result == null) {
                         result = new ArrayList<>();
@@ -6947,8 +6947,7 @@
 
     private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
             String resolvedType, int flags) {
-        PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
-                .get(userId);
+        PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
         //TODO(b/158003772): Remove double query
         List<PersistentPreferredActivity> pprefs = ppir != null
                 ? ppir.queryIntent(intent, resolvedType,
@@ -6967,8 +6966,7 @@
     private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
             int flags, List<ResolveInfo> query, boolean debug, int userId) {
         final int N = query.size();
-        PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
-                .get(userId);
+        PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
         // Get the list of persistent preferred activities that handle the intent
         if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
         List<PersistentPreferredActivity> pprefs = ppir != null
@@ -7068,7 +7066,7 @@
                 return pri;
             }
 
-            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+            PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
             // Get the list of preferred activities that handle the intent
             if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
             List<PreferredActivity> prefs = pir != null
@@ -7295,7 +7293,7 @@
 
     private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
             String resolvedType, int userId) {
-        CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId);
+        CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolvers(userId);
         if (resolver != null) {
             return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
         }
@@ -9897,7 +9895,7 @@
                 android.Manifest.permission.INTERACT_ACROSS_PROFILES,
                 PermissionChecker.PID_UNKNOWN,
                 callingUid,
-                mPmInternal.getPackage(callingUid).getPackageName())
+                getPackage(callingUid).getPackageName())
                 == PermissionChecker.PERMISSION_GRANTED) {
             return;
         }
@@ -13604,11 +13602,12 @@
     int installExistingPackageAsUser(@Nullable String packageName, @UserIdInt int userId,
             @PackageManager.InstallFlags int installFlags,
             @PackageManager.InstallReason int installReason,
-            @Nullable List<String> whiteListedPermissions, @Nullable IntentSender intentSender) {
+            @Nullable List<String> allowlistedRestrictedPermissions,
+            @Nullable IntentSender intentSender) {
         if (DEBUG_INSTALL) {
             Log.v(TAG, "installExistingPackageAsUser package=" + packageName + " userId=" + userId
                     + " installFlags=" + installFlags + " installReason=" + installReason
-                    + " whiteListedPermissions=" + whiteListedPermissions);
+                    + " allowlistedRestrictedPermissions=" + allowlistedRestrictedPermissions);
         }
 
         final int callingUid = Binder.getCallingUid();
@@ -13674,11 +13673,12 @@
                 if (pkgSetting.pkg != null) {
                     if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
                             != 0) {
-                        whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions();
+                        allowlistedRestrictedPermissions = pkgSetting.pkg.getRequestedPermissions();
+                    } else if (allowlistedRestrictedPermissions == null) {
+                        allowlistedRestrictedPermissions = Collections.emptyList();
                     }
-                    mPermissionManager.setAllowlistedRestrictedPermissions(pkgSetting.pkg,
-                            whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER,
-                            new int[] { userId });
+                    mPermissionManager.onPackageInstalled(pkgSetting.pkg, Collections.emptyList(),
+                            allowlistedRestrictedPermissions, MODE_DEFAULT, userId);
                 }
 
                 if (pkgSetting.pkg != null) {
@@ -20453,7 +20453,7 @@
         }
 
         synchronized (mLock) {
-            final PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+            final PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
             if (pir != null) {
                 // Get all of the existing entries that exactly match this filter.
                 final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
@@ -20550,35 +20550,7 @@
     @GuardedBy("mLock")
     private void clearPackagePreferredActivitiesLPw(String packageName,
             @NonNull SparseBooleanArray outUserChanged, int userId) {
-        ArrayList<PreferredActivity> removed = null;
-        for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
-            final int thisUserId = mSettings.mPreferredActivities.keyAt(i);
-            PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
-            if (userId != UserHandle.USER_ALL && userId != thisUserId) {
-                continue;
-            }
-            Iterator<PreferredActivity> it = pir.filterIterator();
-            while (it.hasNext()) {
-                PreferredActivity pa = it.next();
-                // Mark entry for removal only if it matches the package name
-                // and the entry is of type "always".
-                if (packageName == null ||
-                        (pa.mPref.mComponent.getPackageName().equals(packageName)
-                                && pa.mPref.mAlways)) {
-                    if (removed == null) {
-                        removed = new ArrayList<>();
-                    }
-                    removed.add(pa);
-                }
-            }
-            if (removed != null) {
-                for (int j=0; j<removed.size(); j++) {
-                    PreferredActivity pa = removed.get(j);
-                    pir.removeFilter(pa);
-                }
-                outUserChanged.put(thisUserId, true);
-            }
-        }
+        mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId);
     }
 
     /** This method takes a specific user id as well as UserHandle.USER_ALL. */
@@ -20695,7 +20667,7 @@
         final int userId = UserHandle.getCallingUserId();
         // reader
         synchronized (mLock) {
-            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+            PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
             if (pir != null) {
                 final Iterator<PreferredActivity> it = pir.filterIterator();
                 while (it.hasNext()) {
@@ -20750,35 +20722,9 @@
             throw new SecurityException(
                     "clearPackagePersistentPreferredActivities can only be run by the system");
         }
-        ArrayList<PersistentPreferredActivity> removed = null;
         boolean changed = false;
         synchronized (mLock) {
-            for (int i=0; i<mSettings.mPersistentPreferredActivities.size(); i++) {
-                final int thisUserId = mSettings.mPersistentPreferredActivities.keyAt(i);
-                PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
-                        .valueAt(i);
-                if (userId != thisUserId) {
-                    continue;
-                }
-                Iterator<PersistentPreferredActivity> it = ppir.filterIterator();
-                while (it.hasNext()) {
-                    PersistentPreferredActivity ppa = it.next();
-                    // Mark entry for removal only if it matches the package name.
-                    if (ppa.mComponent.getPackageName().equals(packageName)) {
-                        if (removed == null) {
-                            removed = new ArrayList<>();
-                        }
-                        removed.add(ppa);
-                    }
-                }
-                if (removed != null) {
-                    for (int j=0; j<removed.size(); j++) {
-                        PersistentPreferredActivity ppa = removed.get(j);
-                        ppir.removeFilter(ppa);
-                    }
-                    changed = true;
-                }
-            }
+            changed = mSettings.clearPackagePersistentPreferredActivities(packageName, userId);
         }
         if (changed) {
             updateDefaultHomeNotLocked(userId);
@@ -21329,15 +21275,8 @@
 
     @Override
     public @Nullable String getAttentionServicePackageName() {
-        final String flattenedComponentName =
-                mContext.getString(R.string.config_defaultAttentionService);
-        if (flattenedComponentName != null) {
-            ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName);
-            if (componentName != null && componentName.getPackageName() != null) {
-                return ensureSystemPackageName(componentName.getPackageName());
-            }
-        }
-        return null;
+        return ensureSystemPackageName(
+                getPackageFromComponentString(R.string.config_defaultAttentionService));
     }
 
     private @Nullable String getDocumenterPackageName() {
@@ -21372,17 +21311,8 @@
 
     @Override
     public String getAppPredictionServicePackageName() {
-        String flattenedAppPredictionServiceComponentName =
-                mContext.getString(R.string.config_defaultAppPredictionService);
-        if (flattenedAppPredictionServiceComponentName == null) {
-            return null;
-        }
-        ComponentName appPredictionServiceComponentName =
-                ComponentName.unflattenFromString(flattenedAppPredictionServiceComponentName);
-        if (appPredictionServiceComponentName == null) {
-            return null;
-        }
-        return ensureSystemPackageName(appPredictionServiceComponentName.getPackageName());
+        return ensureSystemPackageName(
+                getPackageFromComponentString(R.string.config_defaultAppPredictionService));
     }
 
     private @NonNull String[] dropNonSystemPackages(@NonNull String[] pkgNames) {
@@ -21399,19 +21329,8 @@
 
     @Override
     public String getSystemCaptionsServicePackageName() {
-        String flattenedSystemCaptionsServiceComponentName =
-                mContext.getString(R.string.config_defaultSystemCaptionsService);
-
-        if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) {
-            return null;
-        }
-
-        ComponentName systemCaptionsServiceComponentName =
-                ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName);
-        if (systemCaptionsServiceComponentName == null) {
-            return null;
-        }
-        return ensureSystemPackageName(systemCaptionsServiceComponentName.getPackageName());
+        return ensureSystemPackageName(
+                getPackageFromComponentString(R.string.config_defaultSystemCaptionsService));
     }
 
     @Override
@@ -21429,19 +21348,8 @@
 
     @Override
     public String getContentCaptureServicePackageName() {
-        final String flattenedContentCaptureService =
-                mContext.getString(R.string.config_defaultContentCaptureService);
-
-        if (TextUtils.isEmpty(flattenedContentCaptureService)) {
-            return null;
-        }
-
-        final ComponentName contentCaptureServiceComponentName =
-                ComponentName.unflattenFromString(flattenedContentCaptureService);
-        if (contentCaptureServiceComponentName == null) {
-            return null;
-        }
-        return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName());
+        return ensureSystemPackageName(
+                getPackageFromComponentString(R.string.config_defaultContentCaptureService));
     }
 
     public String getOverlayConfigSignaturePackageName() {
@@ -21485,6 +21393,26 @@
     }
 
     @Nullable
+    private String getRecentsPackageName() {
+        return ensureSystemPackageName(
+                getPackageFromComponentString(R.string.config_recentsComponentName));
+
+    }
+
+    @Nullable
+    private String getPackageFromComponentString(@StringRes int stringResId) {
+        final String componentString = mContext.getString(stringResId);
+        if (TextUtils.isEmpty(componentString)) {
+            return null;
+        }
+        final ComponentName component = ComponentName.unflattenFromString(componentString);
+        if (component == null) {
+            return null;
+        }
+        return component.getPackageName();
+    }
+
+    @Nullable
     private String ensureSystemPackageName(@Nullable String packageName) {
         if (packageName == null) {
             return null;
@@ -22176,33 +22104,9 @@
         }
 
         synchronized (mLock) {
-            // Verify that all of the preferred activity components actually
-            // exist.  It is possible for applications to be updated and at
-            // that point remove a previously declared activity component that
-            // had been set as a preferred activity.  We try to clean this up
-            // the next time we encounter that preferred activity, but it is
-            // possible for the user flow to never be able to return to that
-            // situation so here we do a validity check to make sure we haven't
-            // left any junk around.
-            ArrayList<PreferredActivity> removed = new ArrayList<>();
-            for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
-                PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
-                removed.clear();
-                for (PreferredActivity pa : pir.filterSet()) {
-                    if (!mComponentResolver.isActivityDefined(pa.mPref.mComponent)) {
-                        removed.add(pa);
-                    }
-                }
-                if (removed.size() > 0) {
-                    for (int r=0; r<removed.size(); r++) {
-                        PreferredActivity pa = removed.get(r);
-                        Slog.w(TAG, "Removing dangling preferred activity: "
-                                + pa.mPref.mComponent);
-                        pir.removeFilter(pa);
-                    }
-                    mSettings.writePackageRestrictionsLPr(
-                            mSettings.mPreferredActivities.keyAt(i));
-                }
+            ArrayList<Integer> changed = mSettings.systemReady(mComponentResolver);
+            for (int i = 0; i < changed.size(); i++) {
+                mSettings.writePackageRestrictionsLPr(changed.get(i));
             }
         }
 
@@ -22232,22 +22136,6 @@
         mInstallerService.systemReady();
         mPackageDexOptimizer.systemReady();
 
-        mInjector.getLocalService(StorageManagerInternal.class).addExternalStoragePolicy(
-                new StorageManagerInternal.ExternalStorageMountPolicy() {
-                    @Override
-                    public int getMountMode(int uid, String packageName) {
-                        if (Process.isIsolated(uid)) {
-                            return Zygote.MOUNT_EXTERNAL_NONE;
-                        }
-                        return Zygote.MOUNT_EXTERNAL_DEFAULT;
-                    }
-
-                    @Override
-                    public boolean hasExternalStorage(int uid, String packageName) {
-                        return true;
-                    }
-        });
-
         // Now that we're mostly running, clean up stale users and apps
         mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
         reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
@@ -22729,17 +22617,7 @@
             }
 
             if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
-                for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
-                    PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
-                    int user = mSettings.mPreferredActivities.keyAt(i);
-                    if (pir.dump(pw,
-                            dumpState.getTitlePrinted()
-                                ? "\nPreferred Activities User " + user + ":"
-                                : "Preferred Activities User " + user + ":", "  ",
-                            packageName, true, false)) {
-                        dumpState.setTitlePrinted(true);
-                    }
-                }
+                mSettings.dumpPreferred(pw, dumpState, packageName);
             }
 
             if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
@@ -24838,6 +24716,26 @@
         }
     }
 
+    private AndroidPackage getPackage(String packageName) {
+        synchronized (mLock) {
+            packageName = resolveInternalPackageNameLPr(
+                    packageName, PackageManager.VERSION_CODE_HIGHEST);
+            return mPackages.get(packageName);
+        }
+    }
+
+    private AndroidPackage getPackage(int uid) {
+        synchronized (mLock) {
+            final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
+            AndroidPackage pkg = null;
+            final int numPackages = packageNames == null ? 0 : packageNames.length;
+            for (int i = 0; pkg == null && i < numPackages; i++) {
+                pkg = mPackages.get(packageNames[i]);
+            }
+            return pkg;
+        }
+    }
+
     private class PackageManagerInternalImpl extends PackageManagerInternal {
         @Override
         public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
@@ -24948,24 +24846,12 @@
 
         @Override
         public AndroidPackage getPackage(String packageName) {
-            synchronized (mLock) {
-                packageName = resolveInternalPackageNameLPr(
-                        packageName, PackageManager.VERSION_CODE_HIGHEST);
-                return mPackages.get(packageName);
-            }
+            return PackageManagerService.this.getPackage(packageName);
         }
 
         @Override
         public AndroidPackage getPackage(int uid) {
-            synchronized (mLock) {
-                final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
-                AndroidPackage pkg = null;
-                final int numPackages = packageNames == null ? 0 : packageNames.length;
-                for (int i = 0; pkg == null && i < numPackages; i++) {
-                    pkg = mPackages.get(packageNames[i]);
-                }
-                return pkg;
-            }
+            return PackageManagerService.this.getPackage(uid);
         }
 
         @Nullable
@@ -25092,6 +24978,8 @@
                             : new String[] {mRetailDemoPackage};
                 case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
                     return filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
+                case PackageManagerInternal.PACKAGE_RECENTS:
+                    return filterOnlySystemPackages(mRecentsPackage);
                 default:
                     return ArrayUtils.emptyArray(String.class);
             }
@@ -25570,7 +25458,7 @@
                 }
             }
 
-            PackageManager.invalidatePackageInfoCache();
+            invalidatePackageInfoCache();
             return true;
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageProperty.java b/services/core/java/com/android/server/pm/PackageProperty.java
index d18a02d..ee9ed3b 100644
--- a/services/core/java/com/android/server/pm/PackageProperty.java
+++ b/services/core/java/com/android/server/pm/PackageProperty.java
@@ -274,7 +274,7 @@
 
     private Property getApplicationProperty(String propertyName, String packageName) {
         final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
-                mApplicationProperties.get(propertyName);
+                mApplicationProperties != null ? mApplicationProperties.get(propertyName) : null;
         if (packagePropertyMap == null) {
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 804faa1..ff6b73b 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -252,6 +252,37 @@
         return numMatch == NS;
     }
 
+    public boolean sameSet(PreferredComponent pc) {
+        if (mSetPackages == null || pc == null || pc.mSetPackages == null
+                || !sameComponent(pc.mComponent)) {
+            return false;
+        }
+        final int otherPackageCount = pc.mSetPackages.length;
+        final int packageCount = mSetPackages.length;
+        if (otherPackageCount != packageCount) {
+            return false;
+        }
+        for (int i = 0; i < packageCount; i++) {
+            if (!mSetPackages[i].equals(pc.mSetPackages[i])
+                    || !mSetClasses[i].equals(pc.mSetClasses[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /** Returns true if the preferred component represents the provided ComponentName. */
+    private boolean sameComponent(ComponentName comp) {
+        if (mComponent == null || comp == null) {
+            return false;
+        }
+        if (mComponent.getPackageName().equals(comp.getPackageName())
+                && mComponent.getClassName().equals(comp.getClassName())) {
+            return true;
+        }
+        return false;
+    }
+
     public boolean isSuperset(List<ResolveInfo> query, boolean excludeSetupWizardPackage) {
         if (mSetPackages == null) {
             return query == null;
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index a261e29..ff3df13 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -22,6 +22,7 @@
 import java.io.PrintWriter;
 
 import com.android.server.IntentResolver;
+import java.util.ArrayList;
 
 public class PreferredIntentResolver
         extends IntentResolver<PreferredActivity, PreferredActivity> {
@@ -45,4 +46,24 @@
     protected IntentFilter getIntentFilter(@NonNull PreferredActivity input) {
         return input;
     }
+
+    public boolean shouldAddPreferredActivity(PreferredActivity pa) {
+        ArrayList<PreferredActivity> pal = findFilters(pa);
+        if (pal == null || pal.isEmpty()) {
+            return true;
+        }
+        if (!pa.mPref.mAlways) {
+            return false;
+        }
+        final int activityCount = pal.size();
+        for (int i = 0; i < activityCount; i++) {
+            PreferredActivity cur = pal.get(i);
+            if (cur.mPref.mAlways
+                    && cur.mPref.mMatch == (pa.mPref.mMatch & IntentFilter.MATCH_CATEGORY_MASK)
+                    && cur.mPref.sameSet(pa.mPref)) {
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 966090cb..f47b4b4 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -369,16 +369,16 @@
 
     // The user's preferred activities associated with particular intent
     // filters.
-    final SparseArray<PreferredIntentResolver> mPreferredActivities =
+    private final SparseArray<PreferredIntentResolver> mPreferredActivities =
             new SparseArray<PreferredIntentResolver>();
 
     // The persistent preferred activities of the user's profile/device owner
     // associated with particular intent filters.
-    final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
+    private final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
             new SparseArray<PersistentPreferredIntentResolver>();
 
     // For every user, it is used to find to which other users the intent can be forwarded.
-    final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
+    private final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
             new SparseArray<CrossProfileIntentResolver>();
 
     final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>();
@@ -467,7 +467,7 @@
     }
 
     private static void invalidatePackageCache() {
-        PackageManager.invalidatePackageInfoCache();
+        PackageManagerService.invalidatePackageInfoCache();
         ChangeIdStateCache.invalidate();
     }
 
@@ -1312,8 +1312,7 @@
                 PreferredActivity pa = new PreferredActivity(parser);
                 if (pa.mPref.getParseError() == null) {
                     final PreferredIntentResolver resolver = editPreferredActivitiesLPw(userId);
-                    ArrayList<PreferredActivity> pal = resolver.findFilters(pa);
-                    if (pal == null || pal.size() == 0 || pa.mPref.mAlways) {
+                    if (resolver.shouldAddPreferredActivity(pa)) {
                         resolver.addFilter(pa);
                     }
                 } else {
@@ -5543,4 +5542,130 @@
             }
         }
     }
+
+    /**
+     * Accessor for preferred activities
+     */
+    PersistentPreferredIntentResolver getPersistentPreferredActivities(int userId) {
+        return mPersistentPreferredActivities.get(userId);
+    }
+
+    PreferredIntentResolver getPreferredActivities(int userId) {
+        return mPreferredActivities.get(userId);
+    }
+
+    CrossProfileIntentResolver getCrossProfileIntentResolvers(int userId) {
+        return mCrossProfileIntentResolvers.get(userId);
+    }
+
+    /** This method takes a specific user id as well as UserHandle.USER_ALL. */
+    void clearPackagePreferredActivities(String packageName,
+            @NonNull SparseBooleanArray outUserChanged, int userId) {
+        ArrayList<PreferredActivity> removed = null;
+        for (int i = 0; i < mPreferredActivities.size(); i++) {
+            final int thisUserId = mPreferredActivities.keyAt(i);
+            PreferredIntentResolver pir = mPreferredActivities.valueAt(i);
+            if (userId != UserHandle.USER_ALL && userId != thisUserId) {
+                continue;
+            }
+            Iterator<PreferredActivity> it = pir.filterIterator();
+            while (it.hasNext()) {
+                PreferredActivity pa = it.next();
+                // Mark entry for removal only if it matches the package name
+                // and the entry is of type "always".
+                if (packageName == null
+                        || (pa.mPref.mComponent.getPackageName().equals(packageName)
+                                && pa.mPref.mAlways)) {
+                    if (removed == null) {
+                        removed = new ArrayList<>();
+                    }
+                    removed.add(pa);
+                }
+            }
+            if (removed != null) {
+                for (int j = 0; j < removed.size(); j++) {
+                    PreferredActivity pa = removed.get(j);
+                    pir.removeFilter(pa);
+                }
+                outUserChanged.put(thisUserId, true);
+            }
+        }
+    }
+
+    boolean clearPackagePersistentPreferredActivities(String packageName, int userId) {
+        ArrayList<PersistentPreferredActivity> removed = null;
+        boolean changed = false;
+        for (int i = 0; i < mPersistentPreferredActivities.size(); i++) {
+            final int thisUserId = mPersistentPreferredActivities.keyAt(i);
+            PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.valueAt(i);
+            if (userId != thisUserId) {
+                continue;
+            }
+            Iterator<PersistentPreferredActivity> it = ppir.filterIterator();
+            while (it.hasNext()) {
+                PersistentPreferredActivity ppa = it.next();
+                // Mark entry for removal only if it matches the package name.
+                if (ppa.mComponent.getPackageName().equals(packageName)) {
+                    if (removed == null) {
+                        removed = new ArrayList<>();
+                    }
+                    removed.add(ppa);
+                }
+            }
+            if (removed != null) {
+                for (int j = 0; j < removed.size(); j++) {
+                    PersistentPreferredActivity ppa = removed.get(j);
+                    ppir.removeFilter(ppa);
+                }
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    ArrayList<Integer> systemReady(ComponentResolver resolver) {
+        // Verify that all of the preferred activity components actually
+        // exist.  It is possible for applications to be updated and at
+        // that point remove a previously declared activity component that
+        // had been set as a preferred activity.  We try to clean this up
+        // the next time we encounter that preferred activity, but it is
+        // possible for the user flow to never be able to return to that
+        // situation so here we do a validity check to make sure we haven't
+        // left any junk around.
+        ArrayList<Integer> changed = new ArrayList<>();
+        ArrayList<PreferredActivity> removed = new ArrayList<>();
+        for (int i = 0; i < mPreferredActivities.size(); i++) {
+            PreferredIntentResolver pir = mPreferredActivities.valueAt(i);
+            removed.clear();
+            for (PreferredActivity pa : pir.filterSet()) {
+                if (!resolver.isActivityDefined(pa.mPref.mComponent)) {
+                    removed.add(pa);
+                }
+            }
+            if (removed.size() > 0) {
+                for (int r = 0; r < removed.size(); r++) {
+                    PreferredActivity pa = removed.get(r);
+                    Slog.w(TAG, "Removing dangling preferred activity: "
+                            + pa.mPref.mComponent);
+                    pir.removeFilter(pa);
+                }
+                changed.add(mPreferredActivities.keyAt(i));
+            }
+        }
+        return changed;
+    }
+
+    void dumpPreferred(PrintWriter pw, DumpState dumpState, String packageName) {
+        for (int i = 0; i < mPreferredActivities.size(); i++) {
+            PreferredIntentResolver pir = mPreferredActivities.valueAt(i);
+            int user = mPreferredActivities.keyAt(i);
+            if (pir.dump(pw,
+                         dumpState.getTitlePrinted()
+                         ? "\nPreferred Activities User " + user + ":"
+                         : "Preferred Activities User " + user + ":", "  ",
+                         packageName, true, false)) {
+                dumpState.setTitlePrinted(true);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ShareTargetInfo.java b/services/core/java/com/android/server/pm/ShareTargetInfo.java
index fdfee77..660874e 100644
--- a/services/core/java/com/android/server/pm/ShareTargetInfo.java
+++ b/services/core/java/com/android/server/pm/ShareTargetInfo.java
@@ -17,10 +17,11 @@
 
 import android.annotation.NonNull;
 import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -123,7 +124,7 @@
         return strBuilder.toString();
     }
 
-    void saveToXml(@NonNull XmlSerializer out) throws IOException {
+    void saveToXml(@NonNull TypedXmlSerializer out) throws IOException {
         out.startTag(null, TAG_SHARE_TARGET);
 
         ShortcutService.writeAttr(out, ATTR_TARGET_CLASS, mTargetClass);
@@ -149,7 +150,7 @@
         out.endTag(null, TAG_SHARE_TARGET);
     }
 
-    static ShareTargetInfo loadFromXml(XmlPullParser parser)
+    static ShareTargetInfo loadFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final String targetClass = ShortcutService.parseStringAttribute(parser, ATTR_TARGET_CLASS);
         final ArrayList<ShareTargetInfo.TargetData> targetData = new ArrayList<>();
@@ -178,7 +179,7 @@
                 targetClass, categories.toArray(new String[categories.size()]));
     }
 
-    private static ShareTargetInfo.TargetData parseTargetData(XmlPullParser parser) {
+    private static ShareTargetInfo.TargetData parseTargetData(TypedXmlPullParser parser) {
         final String scheme = ShortcutService.parseStringAttribute(parser, ATTR_SCHEME);
         final String host = ShortcutService.parseStringAttribute(parser, ATTR_HOST);
         final String port = ShortcutService.parseStringAttribute(parser, ATTR_PORT);
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 0ebe5961..2960bc9 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -24,6 +24,8 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -36,15 +38,12 @@
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -225,7 +224,7 @@
      * Persist.
      */
     @Override
-    public void saveToXml(XmlSerializer out, boolean forBackup)
+    public void saveToXml(TypedXmlSerializer out, boolean forBackup)
             throws IOException {
         if (forBackup && !getPackageInfo().isBackupAllowed()) {
             // If an launcher app doesn't support backup&restore, then nothing to do.
@@ -278,11 +277,8 @@
         }
 
         try {
-            final BufferedInputStream bis = new BufferedInputStream(in);
-
             ShortcutLauncher ret = null;
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(bis, StandardCharsets.UTF_8.name());
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
 
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -313,7 +309,7 @@
     /**
      * Load.
      */
-    public static ShortcutLauncher loadFromXml(XmlPullParser parser, ShortcutUser shortcutUser,
+    public static ShortcutLauncher loadFromXml(TypedXmlPullParser parser, ShortcutUser shortcutUser,
             int ownerUserId, boolean fromBackup) throws IOException, XmlPullParserException {
         final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
                 ATTR_PACKAGE_NAME);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index f6c60ad..0ac0c8d 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -35,6 +35,8 @@
 import android.util.AtomicFile;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -52,15 +54,12 @@
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -1571,7 +1570,7 @@
     }
 
     @Override
-    public void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+    public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException {
         final int size = mShortcuts.size();
         final int shareTargetSize = mShareTargets.size();
@@ -1601,7 +1600,7 @@
         out.endTag(null, TAG_ROOT);
     }
 
-    private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup,
+    private void saveShortcut(TypedXmlSerializer out, ShortcutInfo si, boolean forBackup,
             boolean appSupportsBackup)
             throws IOException, XmlPullParserException {
 
@@ -1734,11 +1733,8 @@
         }
 
         try {
-            final BufferedInputStream bis = new BufferedInputStream(in);
-
             ShortcutPackage ret = null;
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(bis, StandardCharsets.UTF_8.name());
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
 
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -1767,7 +1763,7 @@
     }
 
     public static ShortcutPackage loadFromXml(ShortcutService s, ShortcutUser shortcutUser,
-            XmlPullParser parser, boolean fromBackup)
+            TypedXmlPullParser parser, boolean fromBackup)
             throws IOException, XmlPullParserException {
 
         final String packageName = ShortcutService.parseStringAttribute(parser,
@@ -1814,7 +1810,7 @@
         return ret;
     }
 
-    private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName,
+    private static ShortcutInfo parseShortcut(TypedXmlPullParser parser, String packageName,
             @UserIdInt int userId, boolean fromBackup)
             throws IOException, XmlPullParserException {
         String id;
@@ -1948,7 +1944,7 @@
                 disabledReason, persons.toArray(new Person[persons.size()]), locusId);
     }
 
-    private static Intent parseIntent(XmlPullParser parser)
+    private static Intent parseIntent(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
 
         Intent intent = ShortcutService.parseIntentAttribute(parser,
@@ -1978,7 +1974,7 @@
         return intent;
     }
 
-    private static Person parsePerson(XmlPullParser parser)
+    private static Person parsePerson(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         CharSequence name = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_NAME);
         String uri = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_URI);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 8c7871f..fce6610 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -23,6 +23,8 @@
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
@@ -32,7 +34,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -205,7 +206,7 @@
         mSigHashes = BackupUtils.hashSignatureArray(signatures);
     }
 
-    public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
+    public void saveToXml(ShortcutService s, TypedXmlSerializer out, boolean forBackup)
             throws IOException {
         if (forBackup && !mBackupAllowedInitialized) {
             s.wtf("Backup happened before mBackupAllowed is initialized.");
@@ -236,7 +237,7 @@
         out.endTag(null, TAG_ROOT);
     }
 
-    public void loadFromXml(XmlPullParser parser, boolean fromBackup)
+    public void loadFromXml(TypedXmlPullParser parser, boolean fromBackup)
             throws IOException, XmlPullParserException {
         // Don't use the version code from the backup file.
         final long versionCode = ShortcutService.parseLongAttribute(parser, ATTR_VERSION,
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 801c6cb..829133c 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -20,16 +20,15 @@
 import android.content.pm.ShortcutInfo;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
 
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -146,7 +145,7 @@
 
     protected abstract void onRestored(int restoreBlockReason);
 
-    public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+    public abstract void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException;
 
     public void saveToFile(File path, boolean forBackup) {
@@ -154,18 +153,21 @@
         FileOutputStream os = null;
         try {
             os = file.startWrite();
-            final BufferedOutputStream bos = new BufferedOutputStream(os);
 
             // Write to XML
-            XmlSerializer itemOut = new FastXmlSerializer();
-            itemOut.setOutput(bos, StandardCharsets.UTF_8.name());
+            final TypedXmlSerializer itemOut;
+            if (forBackup) {
+                itemOut = Xml.newFastSerializer();
+                itemOut.setOutput(os, StandardCharsets.UTF_8.name());
+            } else {
+                itemOut = Xml.resolveSerializer(os);
+            }
             itemOut.startDocument(null, true);
 
             saveToXml(itemOut, forBackup);
 
             itemOut.endDocument();
 
-            bos.flush();
             os.flush();
             file.finishWrite(os);
         } catch (XmlPullParserException | IOException e) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2d77182..c68fe81 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -95,6 +95,8 @@
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.TypedValue;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.view.IWindowManager;
 
@@ -104,7 +106,6 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.StatLogger;
 import com.android.server.LocalServices;
@@ -119,10 +120,7 @@
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -799,31 +797,31 @@
     // === Persisting ===
 
     @Nullable
-    static String parseStringAttribute(XmlPullParser parser, String attribute) {
+    static String parseStringAttribute(TypedXmlPullParser parser, String attribute) {
         return parser.getAttributeValue(null, attribute);
     }
 
-    static boolean parseBooleanAttribute(XmlPullParser parser, String attribute) {
+    static boolean parseBooleanAttribute(TypedXmlPullParser parser, String attribute) {
         return parseLongAttribute(parser, attribute) == 1;
     }
 
-    static boolean parseBooleanAttribute(XmlPullParser parser, String attribute, boolean def) {
+    static boolean parseBooleanAttribute(TypedXmlPullParser parser, String attribute, boolean def) {
         return parseLongAttribute(parser, attribute, (def ? 1 : 0)) == 1;
     }
 
-    static int parseIntAttribute(XmlPullParser parser, String attribute) {
+    static int parseIntAttribute(TypedXmlPullParser parser, String attribute) {
         return (int) parseLongAttribute(parser, attribute);
     }
 
-    static int parseIntAttribute(XmlPullParser parser, String attribute, int def) {
+    static int parseIntAttribute(TypedXmlPullParser parser, String attribute, int def) {
         return (int) parseLongAttribute(parser, attribute, def);
     }
 
-    static long parseLongAttribute(XmlPullParser parser, String attribute) {
+    static long parseLongAttribute(TypedXmlPullParser parser, String attribute) {
         return parseLongAttribute(parser, attribute, 0);
     }
 
-    static long parseLongAttribute(XmlPullParser parser, String attribute, long def) {
+    static long parseLongAttribute(TypedXmlPullParser parser, String attribute, long def) {
         final String value = parseStringAttribute(parser, attribute);
         if (TextUtils.isEmpty(value)) {
             return def;
@@ -837,7 +835,7 @@
     }
 
     @Nullable
-    static ComponentName parseComponentNameAttribute(XmlPullParser parser, String attribute) {
+    static ComponentName parseComponentNameAttribute(TypedXmlPullParser parser, String attribute) {
         final String value = parseStringAttribute(parser, attribute);
         if (TextUtils.isEmpty(value)) {
             return null;
@@ -846,7 +844,7 @@
     }
 
     @Nullable
-    static Intent parseIntentAttributeNoDefault(XmlPullParser parser, String attribute) {
+    static Intent parseIntentAttributeNoDefault(TypedXmlPullParser parser, String attribute) {
         final String value = parseStringAttribute(parser, attribute);
         Intent parsed = null;
         if (!TextUtils.isEmpty(value)) {
@@ -860,7 +858,7 @@
     }
 
     @Nullable
-    static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
+    static Intent parseIntentAttribute(TypedXmlPullParser parser, String attribute) {
         Intent parsed = parseIntentAttributeNoDefault(parser, attribute);
         if (parsed == null) {
             // Default intent.
@@ -869,7 +867,7 @@
         return parsed;
     }
 
-    static void writeTagValue(XmlSerializer out, String tag, String value) throws IOException {
+    static void writeTagValue(TypedXmlSerializer out, String tag, String value) throws IOException {
         if (TextUtils.isEmpty(value)) return;
 
         out.startTag(null, tag);
@@ -877,16 +875,17 @@
         out.endTag(null, tag);
     }
 
-    static void writeTagValue(XmlSerializer out, String tag, long value) throws IOException {
+    static void writeTagValue(TypedXmlSerializer out, String tag, long value) throws IOException {
         writeTagValue(out, tag, Long.toString(value));
     }
 
-    static void writeTagValue(XmlSerializer out, String tag, ComponentName name) throws IOException {
+    static void writeTagValue(TypedXmlSerializer out, String tag, ComponentName name)
+            throws IOException {
         if (name == null) return;
         writeTagValue(out, tag, name.flattenToString());
     }
 
-    static void writeTagExtra(XmlSerializer out, String tag, PersistableBundle bundle)
+    static void writeTagExtra(TypedXmlSerializer out, String tag, PersistableBundle bundle)
             throws IOException, XmlPullParserException {
         if (bundle == null) return;
 
@@ -895,17 +894,18 @@
         out.endTag(null, tag);
     }
 
-    static void writeAttr(XmlSerializer out, String name, CharSequence value) throws IOException {
+    static void writeAttr(TypedXmlSerializer out, String name, CharSequence value)
+            throws IOException {
         if (TextUtils.isEmpty(value)) return;
 
         out.attribute(null, name, value.toString());
     }
 
-    static void writeAttr(XmlSerializer out, String name, long value) throws IOException {
+    static void writeAttr(TypedXmlSerializer out, String name, long value) throws IOException {
         writeAttr(out, name, String.valueOf(value));
     }
 
-    static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException {
+    static void writeAttr(TypedXmlSerializer out, String name, boolean value) throws IOException {
         if (value) {
             writeAttr(out, name, "1");
         } else {
@@ -913,12 +913,13 @@
         }
     }
 
-    static void writeAttr(XmlSerializer out, String name, ComponentName comp) throws IOException {
+    static void writeAttr(TypedXmlSerializer out, String name, ComponentName comp)
+            throws IOException {
         if (comp == null) return;
         writeAttr(out, name, comp.flattenToString());
     }
 
-    static void writeAttr(XmlSerializer out, String name, Intent intent) throws IOException {
+    static void writeAttr(TypedXmlSerializer out, String name, Intent intent) throws IOException {
         if (intent == null) return;
 
         writeAttr(out, name, intent.toUri(/* flags =*/ 0));
@@ -937,8 +938,7 @@
             outs = file.startWrite();
 
             // Write to XML
-            XmlSerializer out = new FastXmlSerializer();
-            out.setOutput(outs, StandardCharsets.UTF_8.name());
+            TypedXmlSerializer out = Xml.resolveSerializer(outs);
             out.startDocument(null, true);
             out.startTag(null, TAG_ROOT);
 
@@ -966,8 +966,7 @@
             Slog.d(TAG, "Loading from " + file.getBaseFile());
         }
         try (FileInputStream in = file.openRead()) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(in, StandardCharsets.UTF_8.name());
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
 
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -1043,18 +1042,20 @@
     private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
             boolean forBackup) throws IOException, XmlPullParserException {
 
-        final BufferedOutputStream bos = new BufferedOutputStream(os);
-
         // Write to XML
-        XmlSerializer out = new FastXmlSerializer();
-        out.setOutput(bos, StandardCharsets.UTF_8.name());
+        final TypedXmlSerializer out;
+        if (forBackup) {
+            out = Xml.newFastSerializer();
+            out.setOutput(os, StandardCharsets.UTF_8.name());
+        } else {
+            out = Xml.resolveSerializer(os);
+        }
         out.startDocument(null, true);
 
         getUserShortcutsLocked(userId).saveToXml(out, forBackup);
 
         out.endDocument();
 
-        bos.flush();
         os.flush();
     }
 
@@ -1098,11 +1099,14 @@
             boolean fromBackup) throws XmlPullParserException, IOException,
             InvalidFileFormatException {
 
-        final BufferedInputStream bis = new BufferedInputStream(is);
-
         ShortcutUser ret = null;
-        XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(bis, StandardCharsets.UTF_8.name());
+        TypedXmlPullParser parser;
+        if (fromBackup) {
+            parser = Xml.newFastPullParser();
+            parser.setInput(is, StandardCharsets.UTF_8.name());
+        } else {
+            parser = Xml.resolvePullParser(is);
+        }
 
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 5c1d8fb..3e3aa67 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -26,6 +26,8 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
@@ -38,7 +40,6 @@
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.IOException;
@@ -329,7 +330,7 @@
         });
     }
 
-    public void saveToXml(XmlSerializer out, boolean forBackup)
+    public void saveToXml(TypedXmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException {
         out.startTag(null, TAG_ROOT);
 
@@ -371,7 +372,7 @@
         out.endTag(null, TAG_ROOT);
     }
 
-    private void saveShortcutPackageItem(XmlSerializer out, ShortcutPackageItem spi,
+    private void saveShortcutPackageItem(TypedXmlSerializer out, ShortcutPackageItem spi,
             boolean forBackup) throws IOException, XmlPullParserException {
         if (forBackup) {
             if (spi.getPackageUserId() != spi.getOwnerUserId()) {
@@ -408,7 +409,7 @@
         return new File(path, fileName);
     }
 
-    public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
+    public static ShortcutUser loadFromXml(ShortcutService s, TypedXmlPullParser parser, int userId,
             boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
         final ShortcutUser ret = new ShortcutUser(s, userId);
         boolean readShortcutItems = false;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c51e75c..cc814bcc 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -119,7 +119,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -175,6 +174,7 @@
     private static final String ATTR_CONVERTED_FROM_PRE_CREATED = "convertedFromPreCreated";
     private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
     private static final String ATTR_USER_VERSION = "version";
+    private static final String ATTR_USER_TYPE_VERSION = "userTypeConfigVersion";
     private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
     private static final String ATTR_PROFILE_BADGE = "profileBadge";
     private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
@@ -422,6 +422,7 @@
     @GuardedBy("mPackagesLock")
     private int mNextSerialNumber;
     private int mUserVersion = 0;
+    private int mUserTypeVersion = 0;
 
     private IAppOpsService mAppOpsService;
 
@@ -2565,6 +2566,8 @@
                         parser.getAttributeInt(null, ATTR_NEXT_SERIAL_NO, mNextSerialNumber);
                 mUserVersion =
                         parser.getAttributeInt(null, ATTR_USER_VERSION, mUserVersion);
+                mUserTypeVersion =
+                        parser.getAttributeInt(null, ATTR_USER_TYPE_VERSION, mUserTypeVersion);
             }
 
             // Pre-O global user restriction were stored as a single bundle (as opposed to per-user
@@ -2627,7 +2630,7 @@
      */
     @GuardedBy({"mRestrictionsLock", "mPackagesLock"})
     private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) {
-        upgradeIfNecessaryLP(oldGlobalUserRestrictions, mUserVersion);
+        upgradeIfNecessaryLP(oldGlobalUserRestrictions, mUserVersion, mUserTypeVersion);
     }
 
     /**
@@ -2636,9 +2639,11 @@
      */
     @GuardedBy({"mRestrictionsLock", "mPackagesLock"})
     @VisibleForTesting
-    void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions, int userVersion) {
+    void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions, int userVersion,
+            int userTypeVersion) {
         Set<Integer> userIdsToWrite = new ArraySet<>();
         final int originalVersion = mUserVersion;
+        final int originalUserTypeVersion = mUserTypeVersion;
         if (userVersion < 1) {
             // Assign a proper name for the owner, if not initialized correctly before
             UserData userData = getUserDataNoChecks(UserHandle.USER_SYSTEM);
@@ -2771,13 +2776,24 @@
             userVersion = 9;
         }
 
+        // Done with userVersion changes, moving on to deal with userTypeVersion upgrades
+        // Upgrade from previous user type to a new user type
+        final int newUserTypeVersion = UserTypeFactory.getUserTypeVersion();
+        if (newUserTypeVersion > userTypeVersion) {
+            synchronized (mUsersLock) {
+                upgradeUserTypesLU(UserTypeFactory.getUserTypeUpgrades(), mUserTypes,
+                        userTypeVersion, userIdsToWrite);
+            }
+        }
+
         if (userVersion < USER_VERSION) {
             Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
                     + USER_VERSION);
         } else {
             mUserVersion = userVersion;
+            mUserTypeVersion = newUserTypeVersion;
 
-            if (originalVersion < mUserVersion) {
+            if (originalVersion < mUserVersion || originalUserTypeVersion < mUserTypeVersion) {
                 for (int userId : userIdsToWrite) {
                     UserData userData = getUserDataNoChecks(userId);
                     if (userData != null) {
@@ -2801,6 +2817,7 @@
         UserData userData = putUserInfo(system);
         mNextSerialNumber = MIN_USER_ID;
         mUserVersion = USER_VERSION;
+        mUserTypeVersion = UserTypeFactory.getUserTypeVersion();
 
         Bundle restrictions = new Bundle();
         try {
@@ -2991,6 +3008,7 @@
             serializer.startTag(null, TAG_USERS);
             serializer.attributeInt(null, ATTR_NEXT_SERIAL_NO, mNextSerialNumber);
             serializer.attributeInt(null, ATTR_USER_VERSION, mUserVersion);
+            serializer.attributeInt(null, ATTR_USER_TYPE_VERSION, mUserTypeVersion);
 
             serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
             synchronized (mGuestRestrictions) {
@@ -4957,6 +4975,7 @@
 
         // Dump UserTypes
         pw.println();
+        pw.println("User types version: " + mUserTypeVersion);
         pw.println("User types (" + mUserTypes.size() + " types):");
         for (int i = 0; i < mUserTypes.size(); i++) {
             pw.println("    " + mUserTypes.keyAt(i) + ": ");
@@ -5447,6 +5466,9 @@
      * Returns the maximum number of users allowed for the given userTypeDetails per parent user.
      * This is applicable for user types that are {@link UserTypeDetails#isProfile()}.
      * If there is no maximum, {@link UserTypeDetails#UNLIMITED_NUMBER_OF_USERS} is returned.
+     * Under certain circumstances (such as after a change-user-type) the max value can actually
+     * be exceeded: this is allowed in order to keep the device in a usable state.
+     * An error is logged in {@link UserManagerService#upgradeProfileToTypeLU}
      */
     private static int getMaxUsersOfTypePerParent(UserTypeDetails userTypeDetails) {
         final int defaultMax = userTypeDetails.getMaxAllowedPerParent();
@@ -5534,4 +5556,98 @@
         }
         return mDevicePolicyManagerInternal;
     }
+
+    @GuardedBy("mUsersLock")
+    @VisibleForTesting
+    void upgradeUserTypesLU(@NonNull List<UserTypeFactory.UserTypeUpgrade> upgradeOps,
+            @NonNull ArrayMap<String, UserTypeDetails> userTypes,
+            final int formerUserTypeVersion,
+            @NonNull Set<Integer> userIdsToWrite) {
+        for (UserTypeFactory.UserTypeUpgrade userTypeUpgrade : upgradeOps) {
+            if (DBG) {
+                Slog.i(LOG_TAG, "Upgrade: " + userTypeUpgrade.getFromType() + " to: "
+                        + userTypeUpgrade.getToType() + " maxVersion: "
+                        + userTypeUpgrade.getUpToVersion());
+            }
+
+            // upgrade user type if version up to getUpToVersion()
+            if (formerUserTypeVersion <= userTypeUpgrade.getUpToVersion()) {
+                for (int i = 0; i < mUsers.size(); i++) {
+                    UserData userData = mUsers.valueAt(i);
+                    if (userTypeUpgrade.getFromType().equals(userData.info.userType)) {
+                        final UserTypeDetails newUserType = userTypes.get(
+                                userTypeUpgrade.getToType());
+
+                        if (newUserType == null) {
+                            throw new IllegalStateException(
+                                    "Upgrade destination user type not defined: "
+                                            + userTypeUpgrade.getToType());
+                        }
+
+                        upgradeProfileToTypeLU(userData.info, newUserType);
+                        userIdsToWrite.add(userData.info.id);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Changes the user type of a profile to a new user type.
+     * @param userInfo    The user to be updated.
+     * @param newUserType The new user type.
+     */
+    @GuardedBy("mUsersLock")
+    @VisibleForTesting
+    void upgradeProfileToTypeLU(@NonNull UserInfo userInfo, @NonNull UserTypeDetails newUserType) {
+        Slog.i(LOG_TAG, "Upgrading user " + userInfo.id
+                + " from " + userInfo.userType
+                + " to " + newUserType.getName());
+
+        if (!userInfo.isProfile()) {
+            throw new IllegalStateException(
+                    "Can only upgrade profile types. " + userInfo.userType
+                            + " is not a profile type.");
+        }
+
+        // Exceeded maximum profiles for parent user: log error, but allow upgrade
+        if (!canAddMoreProfilesToUser(newUserType.getName(), userInfo.profileGroupId, false)) {
+            Slog.w(LOG_TAG,
+                    "Exceeded maximum profiles of type " + newUserType.getName() + " for user "
+                            + userInfo.id + ". Maximum allowed= "
+                            + newUserType.getMaxAllowedPerParent());
+        }
+
+        final UserTypeDetails oldUserType = mUserTypes.get(userInfo.userType);
+        final int oldFlags;
+        if (oldUserType != null) {
+            oldFlags = oldUserType.getDefaultUserInfoFlags();
+        } else {
+            // if oldUserType is missing from config_user_types.xml -> can only assume FLAG_PROFILE
+            oldFlags = UserInfo.FLAG_PROFILE;
+        }
+
+        //convert userData to newUserType
+        userInfo.userType = newUserType.getName();
+        // remove old default flags and add newUserType's default flags
+        userInfo.flags = newUserType.getDefaultUserInfoFlags() | (userInfo.flags ^ oldFlags);
+
+        // merge existing base restrictions with the new type's default restrictions
+        synchronized (mRestrictionsLock) {
+            if (!UserRestrictionsUtils.isEmpty(newUserType.getDefaultRestrictions())) {
+                final Bundle newRestrictions = UserRestrictionsUtils.clone(
+                        mBaseUserRestrictions.getRestrictions(userInfo.id));
+                UserRestrictionsUtils.merge(newRestrictions,
+                        newUserType.getDefaultRestrictions());
+                updateUserRestrictionsInternalLR(newRestrictions, userInfo.id);
+                if (DBG) {
+                    Slog.i(LOG_TAG, "Updated user " + userInfo.id
+                            + " restrictions to " + newRestrictions);
+                }
+            }
+        }
+
+        // re-compute badge index
+        userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index d0c3a95..0ac3030 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -34,7 +34,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
@@ -670,15 +669,6 @@
                                 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, 0, userId);
                     }
                     break;
-                case UserManager.DISALLOW_CONFIG_LOCATION:
-                    // When DISALLOW_CONFIG_LOCATION is set on any user, we undo the global
-                    // kill switch.
-                    if (newValue) {
-                        android.provider.Settings.Global.putString(
-                                context.getContentResolver(),
-                                Global.LOCATION_GLOBAL_KILL_SWITCH, "0");
-                    }
-                    break;
                 case UserManager.DISALLOW_APPS_CONTROL:
                     // Intentional fall-through
                 case UserManager.DISALLOW_UNINSTALL_APPS:
@@ -774,14 +764,6 @@
                 restriction = UserManager.DISALLOW_AMBIENT_DISPLAY;
                 break;
 
-            case android.provider.Settings.Global.LOCATION_GLOBAL_KILL_SWITCH:
-                if ("0".equals(value)) {
-                    return false;
-                }
-                restriction = UserManager.DISALLOW_CONFIG_LOCATION;
-                checkAllUser = true;
-                break;
-
             case android.provider.Settings.System.SCREEN_BRIGHTNESS:
             case android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT:
             case android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE:
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index d840e5d..5fa46b9 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -174,6 +174,9 @@
     /**
      * Returns the maximum number of this user type allowed per parent (for user types, like
      * profiles, that have parents).
+     * Under certain circumstances (such as after a change-user-type) the max value can actually
+     * be exceeded: this is allowed in order to keep the device in a usable state.
+     * An error is logged in {@link UserManagerService#upgradeProfileToTypeLU}
      * <p>Returns {@link #UNLIMITED_NUMBER_OF_USERS} to indicate that there is no hard limit.
      */
     public int getMaxAllowedPerParent() {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index ba8a2ba..1d3aecd 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -49,6 +49,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 
 /**
@@ -73,14 +74,7 @@
      * @return mapping from the name of each user type to its {@link UserTypeDetails} object
      */
     public static ArrayMap<String, UserTypeDetails> getUserTypes() {
-        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
-        builders.put(USER_TYPE_PROFILE_MANAGED, getDefaultTypeProfileManaged());
-        builders.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeFullSystem());
-        builders.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary());
-        builders.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest());
-        builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo());
-        builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted());
-        builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless());
+        final ArrayMap<String, UserTypeDetails.Builder> builders = getDefaultBuilders();
 
         try (XmlResourceParser parser =
                      Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) {
@@ -94,6 +88,20 @@
         return types;
     }
 
+    private static ArrayMap<String, UserTypeDetails.Builder> getDefaultBuilders() {
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+
+        builders.put(USER_TYPE_PROFILE_MANAGED, getDefaultTypeProfileManaged());
+        builders.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeFullSystem());
+        builders.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary());
+        builders.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest());
+        builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo());
+        builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted());
+        builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless());
+
+        return builders;
+    }
+
     /**
      * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_MANAGED}
      * configuration.
@@ -232,6 +240,10 @@
                     isProfile = true;
                 } else if ("full-type".equals(elementName)) {
                     isProfile = false;
+                } else if ("change-user-type".equals(elementName)) {
+                    // parsed in parseUserUpgrades
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
                 } else {
                     Slog.w(LOG_TAG, "Skipping unknown element " + elementName + " in "
                                 + parser.getPositionDescription());
@@ -291,7 +303,8 @@
                 while (XmlUtils.nextElementWithin(parser, depth)) {
                     final String childName = parser.getName();
                     if ("default-restrictions".equals(childName)) {
-                        final Bundle restrictions = UserRestrictionsUtils.readRestrictions(parser);
+                        final Bundle restrictions = UserRestrictionsUtils
+                                .readRestrictions(XmlUtils.makeTyped(parser));
                         builder.setDefaultRestrictions(restrictions);
                     } else if (isProfile && "badge-labels".equals(childName)) {
                         setResAttributeArray(parser, builder::setBadgeLabels);
@@ -387,4 +400,132 @@
         }
         fcn.accept(result);
     }
+
+    /**
+     * Returns the user type version of the config XML file.
+     * @return user type version defined in XML file, 0 if none.
+     */
+    public static int getUserTypeVersion() {
+        try (XmlResourceParser parser =
+                     Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) {
+            return getUserTypeVersion(parser);
+        }
+    }
+
+    @VisibleForTesting
+    static int getUserTypeVersion(XmlResourceParser parser) {
+        int version = 0;
+
+        try {
+            XmlUtils.beginDocument(parser, "user-types");
+            String versionValue = parser.getAttributeValue(null, "version");
+            if (versionValue != null) {
+                try {
+                    version = Integer.parseInt(versionValue);
+                } catch (NumberFormatException e) {
+                    Slog.e(LOG_TAG, "Cannot parse value of '" + versionValue + "' for version in "
+                            + parser.getPositionDescription(), e);
+                    throw e;
+                }
+            }
+        } catch (XmlPullParserException | IOException e) {
+            Slog.w(LOG_TAG, "Cannot read user type configuration file.", e);
+        }
+
+        return version;
+    }
+
+    /**
+     * Obtains the user type upgrades for this device.
+     * @return The list of user type upgrades.
+     */
+    public static List<UserTypeUpgrade> getUserTypeUpgrades() {
+        final List<UserTypeUpgrade> userUpgrades;
+        try (XmlResourceParser parser =
+                     Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) {
+            userUpgrades = parseUserUpgrades(getDefaultBuilders(), parser);
+        }
+        return userUpgrades;
+    }
+
+    @VisibleForTesting
+    static List<UserTypeUpgrade> parseUserUpgrades(
+            ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser) {
+        final List<UserTypeUpgrade> userUpgrades = new ArrayList<>();
+
+        try {
+            XmlUtils.beginDocument(parser, "user-types");
+            for (XmlUtils.nextElement(parser);
+                    parser.getEventType() != XmlResourceParser.END_DOCUMENT;
+                    XmlUtils.nextElement(parser)) {
+                final String elementName = parser.getName();
+                if ("change-user-type".equals(elementName)) {
+                    final String fromType = parser.getAttributeValue(null, "from");
+                    final String toType = parser.getAttributeValue(null, "to");
+                    // Check that the base type doesn't change.
+                    // Currently, only the base type of PROFILE is supported.
+                    validateUserTypeIsProfile(fromType, builders);
+                    validateUserTypeIsProfile(toType, builders);
+
+                    final int maxVersionToConvert;
+                    try {
+                        maxVersionToConvert = Integer.parseInt(
+                                parser.getAttributeValue(null, "whenVersionLeq"));
+                    } catch (NumberFormatException e) {
+                        Slog.e(LOG_TAG, "Cannot parse value of whenVersionLeq in "
+                                + parser.getPositionDescription(), e);
+                        throw e;
+                    }
+
+                    UserTypeUpgrade userTypeUpgrade = new UserTypeUpgrade(fromType, toType,
+                            maxVersionToConvert);
+                    userUpgrades.add(userTypeUpgrade);
+                    continue;
+                } else {
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+            }
+        } catch (XmlPullParserException | IOException e) {
+            Slog.w(LOG_TAG, "Cannot read user type configuration file.", e);
+        }
+
+        return userUpgrades;
+    }
+
+    private static void validateUserTypeIsProfile(String userType,
+            ArrayMap<String, UserTypeDetails.Builder> builders) {
+        UserTypeDetails.Builder builder = builders.get(userType);
+        if (builder != null && builder.getBaseType() != FLAG_PROFILE) {
+            throw new IllegalArgumentException("Illegal upgrade of user type " + userType
+                    + " : Can only upgrade profiles user types");
+        }
+    }
+
+    /**
+     * Contains details required for an upgrade operation for {@link UserTypeDetails};
+     */
+    public static class UserTypeUpgrade {
+        private final String mFromType;
+        private final String mToType;
+        private final int mUpToVersion;
+
+        public UserTypeUpgrade(String fromType, String toType, int upToVersion) {
+            mFromType = fromType;
+            mToType = toType;
+            mUpToVersion = upToVersion;
+        }
+
+        public String getFromType() {
+            return mFromType;
+        }
+
+        public String getToType() {
+            return mToType;
+        }
+
+        public int getUpToVersion() {
+            return mUpToVersion;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 0a56e13..ab25a7c 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -94,7 +94,7 @@
                 SharedLibraryInfo.TYPE_STATIC,
                 new VersionedPackage(pkg.getManifestPackageName(),
                         pkg.getLongVersionCode()),
-                null, null);
+                null, null, false /* isNative */);
     }
 
     public static SharedLibraryInfo createSharedLibraryForDynamic(AndroidPackage pkg, String name) {
@@ -103,7 +103,7 @@
                 SharedLibraryInfo.VERSION_UNDEFINED,
                 SharedLibraryInfo.TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(),
                 pkg.getLongVersionCode()),
-                null, null);
+                null, null, false /* isNative */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e5c93a3..1656472 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -63,6 +63,7 @@
 import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
+import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
@@ -72,7 +73,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -766,9 +766,14 @@
             grantSystemFixedPermissionsToSystemPackage(pm, wearPackage, userId, PHONE_PERMISSIONS);
 
             // Fitness tracking on watches
-            grantPermissionsToSystemPackage(pm,
+            if (mContext.getResources().getBoolean(R.bool.config_trackerAppNeedsPermissions)) {
+                Log.d(TAG, "Wear: Skipping permission grant for Default fitness tracker app : "
+                        + wearPackage);
+            } else {
+                grantPermissionsToSystemPackage(pm,
                     getDefaultSystemHandlerActivityPackage(pm, ACTION_TRACK, userId), userId,
                     SENSORS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
+            }
         }
 
         // Print Spooler
@@ -1408,11 +1413,8 @@
                 Slog.w(TAG, "Default permissions file " + file + " cannot be read");
                 continue;
             }
-            try (
-                InputStream str = new BufferedInputStream(new FileInputStream(file))
-            ) {
-                TypedXmlPullParser parser = Xml.newFastPullParser();
-                parser.setInput(str, null);
+            try (InputStream str = new FileInputStream(file)) {
+                TypedXmlPullParser parser = Xml.resolvePullParser(str);
                 parse(pm, parser, grantExceptions);
             } catch (XmlPullParserException | IOException e) {
                 Slog.w(TAG, "Error reading default permissions file " + file, e);
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 687e96c..995b59e 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -331,6 +331,10 @@
         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0;
     }
 
+    public boolean isRecents() {
+        return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RECENTS) != 0;
+    }
+
     public void transfer(@NonNull String oldPackageName, @NonNull String newPackageName) {
         if (!oldPackageName.equals(mPermissionInfo.packageName)) {
             return;
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 1b35d29..52bb3d7 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -205,6 +205,9 @@
     private static final int USER_PERMISSION_FLAGS = FLAG_PERMISSION_USER_SET
             | FLAG_PERMISSION_USER_FIXED;
 
+    /** All storage permissions */
+    private static final List<String> STORAGE_PERMISSIONS = new ArrayList<>();
+
     /** If the permission of the value is granted, so is the key */
     private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>();
 
@@ -213,6 +216,9 @@
                 Manifest.permission.ACCESS_FINE_LOCATION);
         FULLER_PERMISSION_MAP.put(Manifest.permission.INTERACT_ACROSS_USERS,
                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+        STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+        STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
     }
 
     /** Lock to protect internal data access */
@@ -1243,50 +1249,56 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            synchronized (mLock) {
-                final UidPermissionState uidState = getUidStateLocked(pkg, userId);
-                if (uidState == null) {
-                    Slog.e(TAG, "Missing permissions state for " + packageName + " and user "
-                            + userId);
-                    return null;
-                }
-
-                int queryFlags = 0;
-                if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
-                    queryFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
-                }
-                if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
-                    queryFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
-                }
-                if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
-                    queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-                }
-                if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
-                    queryFlags |=  FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-                }
-
-                ArrayList<String> whitelistedPermissions = null;
-
-                final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
-                for (int i = 0; i < permissionCount; i++) {
-                    final String permissionName = pkg.getRequestedPermissions().get(i);
-                    final int currentFlags =
-                            uidState.getPermissionFlags(permissionName);
-                    if ((currentFlags & queryFlags) != 0) {
-                        if (whitelistedPermissions == null) {
-                            whitelistedPermissions = new ArrayList<>();
-                        }
-                        whitelistedPermissions.add(permissionName);
-                    }
-                }
-
-                return whitelistedPermissions;
-            }
+            return getAllowlistedRestrictedPermissionsInternal(pkg, flags, userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
+    @Nullable
+    private List<String> getAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
+            @PermissionWhitelistFlags int flags, @UserIdInt int userId) {
+        synchronized (mLock) {
+            final UidPermissionState uidState = getUidStateLocked(pkg, userId);
+            if (uidState == null) {
+                Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+                        + userId);
+                return null;
+            }
+
+            int queryFlags = 0;
+            if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
+                queryFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+            }
+            if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
+                queryFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+            }
+            if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
+                queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+            }
+            if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
+                queryFlags |=  FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+            }
+
+            ArrayList<String> allowlistedPermissions = null;
+
+            final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
+            for (int i = 0; i < permissionCount; i++) {
+                final String permissionName = pkg.getRequestedPermissions().get(i);
+                final int currentFlags =
+                        uidState.getPermissionFlags(permissionName);
+                if ((currentFlags & queryFlags) != 0) {
+                    if (allowlistedPermissions == null) {
+                        allowlistedPermissions = new ArrayList<>();
+                    }
+                    allowlistedPermissions.add(permissionName);
+                }
+            }
+
+            return allowlistedPermissions;
+        }
+    }
+
     @Override
     public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
             @NonNull String permName, @PermissionWhitelistFlags int flags,
@@ -1429,8 +1441,7 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            setAllowlistedRestrictedPermissionsInternal(pkg, permissions, flags,
-                    new int[] { userId });
+            setAllowlistedRestrictedPermissionsInternal(pkg, permissions, flags, userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -1453,13 +1464,6 @@
         return setAutoRevokeExemptedInternal(pkg, whitelisted, userId);
     }
 
-    private void setAutoRevokeExemptedInternal(@NonNull AndroidPackage pkg, boolean exempted,
-            @NonNull int[] userIds) {
-        for (final int userId : userIds) {
-            setAutoRevokeExemptedInternal(pkg, exempted, userId);
-        }
-    }
-
     private boolean setAutoRevokeExemptedInternal(@NonNull AndroidPackage pkg, boolean exempted,
             @UserIdInt int userId) {
         final int packageUid = UserHandle.getUid(userId, pkg.getUid());
@@ -2358,6 +2362,48 @@
     }
 
     /**
+     * If the app is updated, and has scoped storage permissions, then it is possible that the
+     * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+     * @param newPackage The new package that was installed
+     * @param oldPackage The old package that was updated
+     */
+    private void revokeStoragePermissionsIfScopeExpandedInternal(
+            @NonNull AndroidPackage newPackage,
+            @NonNull AndroidPackage oldPackage) {
+        boolean downgradedSdk = oldPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q
+                && newPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q;
+        boolean upgradedSdk = oldPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q
+                && newPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q;
+        boolean newlyRequestsLegacy = !upgradedSdk && !oldPackage.isRequestLegacyExternalStorage()
+                && newPackage.isRequestLegacyExternalStorage();
+
+        if (!newlyRequestsLegacy && !downgradedSdk) {
+            return;
+        }
+
+        final int callingUid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(newPackage.getUid());
+        int numRequestedPermissions = newPackage.getRequestedPermissions().size();
+        for (int i = 0; i < numRequestedPermissions; i++) {
+            PermissionInfo permInfo = getPermissionInfo(newPackage.getRequestedPermissions().get(i),
+                    newPackage.getPackageName(), 0);
+            if (permInfo == null || !STORAGE_PERMISSIONS.contains(permInfo.name)) {
+                continue;
+            }
+
+            EventLog.writeEvent(0x534e4554, "171430330", newPackage.getUid(),
+                    "Revoking permission " + permInfo.name + " from package "
+                            + newPackage.getPackageName() + " as either the sdk downgraded "
+                            + downgradedSdk + " or newly requested legacy full storage "
+                            + newlyRequestsLegacy);
+
+            revokeRuntimePermissionInternal(permInfo.name, newPackage.getPackageName(),
+                    false, callingUid, userId, null, mDefaultPermissionCallback);
+        }
+
+    }
+
+    /**
      * We might auto-grant permissions if any permission of the group is already granted. Hence if
      * the group of a granted permission changes we need to revoke it to avoid having permissions of
      * the new group auto-granted.
@@ -3616,6 +3662,13 @@
             // Special permission granted only to the OEM specified retail demo app
             allowed = true;
         }
+        if (!allowed && bp.isRecents()
+                && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
+                PackageManagerInternal.PACKAGE_RECENTS, UserHandle.USER_SYSTEM),
+                pkg.getPackageName())) {
+            // Special permission for the recents app.
+            allowed = true;
+        }
         return allowed;
     }
 
@@ -3768,13 +3821,6 @@
     }
 
     private void grantRequestedRuntimePermissionsInternal(@NonNull AndroidPackage pkg,
-            @Nullable List<String> permissions, @NonNull int[] userIds) {
-        for (int userId : userIds) {
-            grantRequestedRuntimePermissionsForUser(pkg, permissions, userId);
-        }
-    }
-
-    private void grantRequestedRuntimePermissionsForUser(@NonNull AndroidPackage pkg,
             @Nullable List<String> permissions, int userId) {
         final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                 | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3821,25 +3867,136 @@
 
     private void setAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
             @Nullable List<String> permissions, @PermissionWhitelistFlags int allowlistFlags,
-            @UserIdInt int[] userIds) {
-        SparseArray<ArraySet<String>> oldGrantedRestrictedPermissions = new SparseArray<>();
+            @UserIdInt int userId) {
+        ArraySet<String> oldGrantedRestrictedPermissions = null;
         boolean updatePermissions = false;
         final int permissionCount = pkg.getRequestedPermissions().size();
         final int myUid = Process.myUid();
 
-        for (int i = 0; i < userIds.length; i++) {
-            int userId = userIds[i];
+        for (int j = 0; j < permissionCount; j++) {
+            final String permissionName = pkg.getRequestedPermissions().get(j);
 
-            for (int j = 0; j < permissionCount; j++) {
-                final String permissionName = pkg.getRequestedPermissions().get(j);
+            final boolean isGranted;
+            synchronized (mLock) {
+                final Permission bp = mRegistry.getPermission(permissionName);
+                if (bp == null || !bp.isHardOrSoftRestricted()) {
+                    continue;
+                }
 
+                final UidPermissionState uidState = getUidStateLocked(pkg, userId);
+                if (uidState == null) {
+                    Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
+                            + " and user " + userId);
+                    continue;
+                }
+                isGranted = uidState.isPermissionGranted(permissionName);
+            }
+
+            if (isGranted) {
+                if (oldGrantedRestrictedPermissions == null) {
+                    oldGrantedRestrictedPermissions = new ArraySet<>();
+                }
+                oldGrantedRestrictedPermissions.add(permissionName);
+            }
+
+            final int oldFlags = getPermissionFlagsInternal(permissionName,
+                    pkg.getPackageName(), myUid, userId);
+
+            int newFlags = oldFlags;
+            int mask = 0;
+            int whitelistFlagsCopy = allowlistFlags;
+            while (whitelistFlagsCopy != 0) {
+                final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
+                whitelistFlagsCopy &= ~flag;
+                switch (flag) {
+                    case FLAG_PERMISSION_WHITELIST_SYSTEM: {
+                        mask |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+                        if (permissions != null && permissions.contains(permissionName)) {
+                            newFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+                        } else {
+                            newFlags &= ~FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+                        }
+                    }
+                    break;
+                    case FLAG_PERMISSION_WHITELIST_UPGRADE: {
+                        mask |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+                        if (permissions != null && permissions.contains(permissionName)) {
+                            newFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+                        } else {
+                            newFlags &= ~FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+                        }
+                    }
+                    break;
+                    case FLAG_PERMISSION_WHITELIST_INSTALLER: {
+                        mask |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+                        if (permissions != null && permissions.contains(permissionName)) {
+                            newFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+                        } else {
+                            newFlags &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+                        }
+                    }
+                    break;
+                    case FLAG_PERMISSION_ALLOWLIST_ROLE: {
+                        mask |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+                        if (permissions != null && permissions.contains(permissionName)) {
+                            newFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+                        } else {
+                            newFlags &= ~FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+                        }
+                    }
+                    break;
+                }
+            }
+
+            if (oldFlags == newFlags) {
+                continue;
+            }
+
+            updatePermissions = true;
+
+            final boolean wasWhitelisted = (oldFlags
+                    & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+            final boolean isWhitelisted = (newFlags
+                    & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+
+            // If the permission is policy fixed as granted but it is no longer
+            // on any of the whitelists we need to clear the policy fixed flag
+            // as whitelisting trumps policy i.e. policy cannot grant a non
+            // grantable permission.
+            if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+                if (!isWhitelisted && isGranted) {
+                    mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+                    newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+                }
+            }
+
+            // If we are whitelisting an app that does not support runtime permissions
+            // we need to make sure it goes through the permission review UI at launch.
+            if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
+                    && !wasWhitelisted && isWhitelisted) {
+                mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+                newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+            }
+
+            updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags,
+                    myUid, userId, false, null /*callback*/);
+        }
+
+        if (updatePermissions) {
+            // Update permission of this app to take into account the new whitelist state.
+            restorePermissionState(pkg, false, pkg.getPackageName(), mDefaultPermissionCallback);
+
+            // If this resulted in losing a permission we need to kill the app.
+            if (oldGrantedRestrictedPermissions == null) {
+                return;
+            }
+
+            final int oldGrantedCount = oldGrantedRestrictedPermissions.size();
+            for (int j = 0; j < oldGrantedCount; j++) {
+                final String permissionName = oldGrantedRestrictedPermissions.valueAt(j);
+                // Sometimes we create a new permission state instance during update.
                 final boolean isGranted;
                 synchronized (mLock) {
-                    final Permission bp = mRegistry.getPermission(permissionName);
-                    if (bp == null || !bp.isHardOrSoftRestricted()) {
-                        continue;
-                    }
-
                     final UidPermissionState uidState = getUidStateLocked(pkg, userId);
                     if (uidState == null) {
                         Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
@@ -3848,128 +4005,9 @@
                     }
                     isGranted = uidState.isPermissionGranted(permissionName);
                 }
-
-                if (isGranted) {
-                    if (oldGrantedRestrictedPermissions.get(userId) == null) {
-                        oldGrantedRestrictedPermissions.put(userId, new ArraySet<>());
-                    }
-                    oldGrantedRestrictedPermissions.get(userId).add(permissionName);
-                }
-
-                final int oldFlags = getPermissionFlagsInternal(permissionName,
-                        pkg.getPackageName(), myUid, userId);
-
-                int newFlags = oldFlags;
-                int mask = 0;
-                int whitelistFlagsCopy = allowlistFlags;
-                while (whitelistFlagsCopy != 0) {
-                    final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
-                    whitelistFlagsCopy &= ~flag;
-                    switch (flag) {
-                        case FLAG_PERMISSION_WHITELIST_SYSTEM: {
-                            mask |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
-                            if (permissions != null && permissions.contains(permissionName)) {
-                                newFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
-                            } else {
-                                newFlags &= ~FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
-                            }
-                        }
-                        break;
-                        case FLAG_PERMISSION_WHITELIST_UPGRADE: {
-                            mask |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
-                            if (permissions != null && permissions.contains(permissionName)) {
-                                newFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
-                            } else {
-                                newFlags &= ~FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
-                            }
-                        }
-                        break;
-                        case FLAG_PERMISSION_WHITELIST_INSTALLER: {
-                            mask |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-                            if (permissions != null && permissions.contains(permissionName)) {
-                                newFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-                            } else {
-                                newFlags &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-                            }
-                        }
-                        break;
-                        case FLAG_PERMISSION_ALLOWLIST_ROLE: {
-                            mask |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-                            if (permissions != null && permissions.contains(permissionName)) {
-                                newFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-                            } else {
-                                newFlags &= ~FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-                            }
-                        }
-                        break;
-                    }
-                }
-
-                if (oldFlags == newFlags) {
-                    continue;
-                }
-
-                updatePermissions = true;
-
-                final boolean wasWhitelisted = (oldFlags
-                        & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
-                final boolean isWhitelisted = (newFlags
-                        & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
-
-                // If the permission is policy fixed as granted but it is no longer
-                // on any of the whitelists we need to clear the policy fixed flag
-                // as whitelisting trumps policy i.e. policy cannot grant a non
-                // grantable permission.
-                if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
-                    if (!isWhitelisted && isGranted) {
-                        mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-                        newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-                    }
-                }
-
-                // If we are whitelisting an app that does not support runtime permissions
-                // we need to make sure it goes through the permission review UI at launch.
-                if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
-                        && !wasWhitelisted && isWhitelisted) {
-                    mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
-                    newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
-                }
-
-                updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags,
-                        myUid, userId, false, null /*callback*/);
-            }
-        }
-
-        if (updatePermissions) {
-            // Update permission of this app to take into account the new whitelist state.
-            restorePermissionState(pkg, false, pkg.getPackageName(), mDefaultPermissionCallback);
-
-            // If this resulted in losing a permission we need to kill the app.
-            for (int i = 0; i < userIds.length; i++) {
-                int userId = userIds[i];
-                ArraySet<String> oldPermsForUser = oldGrantedRestrictedPermissions.get(userId);
-                if (oldPermsForUser == null) {
-                    continue;
-                }
-
-                final int oldGrantedCount = oldPermsForUser.size();
-                for (int j = 0; j < oldGrantedCount; j++) {
-                    final String permissionName = oldPermsForUser.valueAt(j);
-                    // Sometimes we create a new permission state instance during update.
-                    final boolean isGranted;
-                    synchronized (mLock) {
-                        final UidPermissionState uidState = getUidStateLocked(pkg, userId);
-                        if (uidState == null) {
-                            Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
-                                    + " and user " + userId);
-                            continue;
-                        }
-                        isGranted = uidState.isPermissionGranted(permissionName);
-                    }
-                    if (!isGranted) {
-                        mDefaultPermissionCallback.onPermissionRevoked(pkg.getUid(), userId, null);
-                        break;
-                    }
+                if (!isGranted) {
+                    mDefaultPermissionCallback.onPermissionRevoked(pkg.getUid(), userId, null);
+                    break;
                 }
             }
         }
@@ -4877,6 +4915,7 @@
             AsyncTask.execute(() -> {
                 if (hasOldPkg) {
                     revokeRuntimePermissionsIfGroupChangedInternal(pkg, oldPkg);
+                    revokeStoragePermissionsIfScopeExpandedInternal(pkg, oldPkg);
                 }
                 if (hasPermissionDefinitionChanges) {
                     revokeRuntimePermissionsIfPermissionDefinitionChangedInternal(
@@ -4907,6 +4946,34 @@
         return true;
     }
 
+    private void onPackageInstalledInternal(@NonNull AndroidPackage pkg,
+            @NonNull List<String> grantedPermissions,
+            @NonNull List<String> allowlistedRestrictedPermissions, int autoRevokePermissionsMode,
+            @UserIdInt int userId) {
+        addAllowlistedRestrictedPermissionsInternal(pkg, allowlistedRestrictedPermissions,
+                FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
+        if (autoRevokePermissionsMode == AppOpsManager.MODE_ALLOWED
+                || autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED) {
+            setAutoRevokeExemptedInternal(pkg,
+                    autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED, userId);
+        }
+        grantRequestedRuntimePermissionsInternal(pkg, grantedPermissions, userId);
+    }
+
+    private void addAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
+            @NonNull List<String> allowlistedRestrictedPermissions,
+            @PermissionWhitelistFlags int flags, @UserIdInt int userId) {
+        List<String> permissions = getAllowlistedRestrictedPermissionsInternal(pkg, flags, userId);
+        if (permissions != null) {
+            ArraySet<String> permissionSet = new ArraySet<>(permissions);
+            permissionSet.addAll(allowlistedRestrictedPermissions);
+            permissions = new ArrayList<>(permissionSet);
+        } else {
+            permissions = allowlistedRestrictedPermissions;
+        }
+        setAllowlistedRestrictedPermissionsInternal(pkg, permissions, flags, userId);
+    }
+
     private void onPackageRemovedInternal(@NonNull AndroidPackage pkg) {
         removeAllPermissionsInternal(pkg);
     }
@@ -5073,28 +5140,6 @@
             return PermissionManagerService.this.getAppOpPermissionPackagesInternal(permissionName);
         }
         @Override
-        public void grantRequestedRuntimePermissions(@NonNull AndroidPackage pkg,
-                @Nullable List<String> permissions, @NonNull int[] userIds) {
-            Objects.requireNonNull(pkg, "pkg");
-            Objects.requireNonNull(userIds, "userIds");
-            grantRequestedRuntimePermissionsInternal(pkg, permissions, userIds);
-        }
-        @Override
-        public void setAllowlistedRestrictedPermissions(@NonNull AndroidPackage pkg,
-                @Nullable List<String> permissions, @PermissionWhitelistFlags int allowlistFlags,
-                @NonNull int[] userIds) {
-            Objects.requireNonNull(pkg, "pkg");
-            Objects.requireNonNull(userIds, "userIds");
-            setAllowlistedRestrictedPermissionsInternal(pkg, permissions, allowlistFlags, userIds);
-        }
-        @Override
-        public void setAutoRevokeExempted(@NonNull AndroidPackage pkg, boolean exempted,
-                @NonNull int[] userIds) {
-            Objects.requireNonNull(pkg, "pkg");
-            Objects.requireNonNull(userIds, "userIds");
-            setAutoRevokeExemptedInternal(pkg, exempted, userIds);
-        }
-        @Override
         public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
             PermissionManagerService.this
                     .updatePermissions(packageName, pkg, mDefaultPermissionCallback);
@@ -5365,6 +5410,20 @@
         }
 
         @Override
+        public void onPackageInstalled(@NonNull AndroidPackage pkg,
+                @NonNull List<String> grantedPermissions,
+                @NonNull List<String> allowlistedRestrictedPermissions,
+                int autoRevokePermissionsMode, @UserIdInt int userId) {
+            Objects.requireNonNull(pkg, "pkg");
+            Objects.requireNonNull(grantedPermissions, "grantedPermissions");
+            Objects.requireNonNull(allowlistedRestrictedPermissions,
+                    "allowlistedRestrictedPermissions");
+            Preconditions.checkArgumentNonNegative(userId, "userId");
+            onPackageInstalledInternal(pkg, grantedPermissions, allowlistedRestrictedPermissions,
+                    autoRevokePermissionsMode, userId);
+        }
+
+        @Override
         public void onPackageRemoved(@NonNull AndroidPackage pkg) {
             Objects.requireNonNull(pkg);
             onPackageRemovedInternal(pkg);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 1becbed..457fe36 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.content.pm.PackageManager;
 import android.content.pm.PermissionInfo;
 import android.permission.PermissionManagerInternal;
 
@@ -190,42 +189,6 @@
             @UserIdInt int userId);
 
     /**
-     * Grant the requested runtime permissions for a package, or an explicit subset of them.
-     *
-     * @param pkg the package
-     * @param permissions the names of the subset of permissions to be granted, or {@code null} for
-     *                    granting all the requested permissions
-     * @param userIds the user IDs
-     */
-    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void grantRequestedRuntimePermissions(@NonNull AndroidPackage pkg,
-            @Nullable List<String> permissions, @NonNull int[] userIds);
-
-    /**
-     * Set the allowlisted restricted permissions for a package, or an explicit subset of them.
-     *
-     * @param pkg the package
-     * @param permissions the names of the subset of permissions to be allowlisted, or {@code null}
-     *                    for allowlisting all the requested restricted permissions
-     * @param userIds the user IDs
-     */
-    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void setAllowlistedRestrictedPermissions(
-            @NonNull AndroidPackage pkg, @Nullable List<String> permissions,
-            @PackageManager.PermissionWhitelistFlags int allowlistFlags, @NonNull int[] userIds);
-
-    /**
-     * Set whether a package is exempted from auto revoke.
-     *
-     * @param pkg the package
-     * @param exempted whether the package is exempted from auto revoke
-     * @param userIds the user IDs
-     */
-    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void setAutoRevokeExempted(@NonNull AndroidPackage pkg, boolean exempted,
-            @NonNull int[] userIds);
-
-    /**
      * Update permissions when a package changed.
      *
      * <p><ol>
@@ -526,6 +489,21 @@
             @Nullable AndroidPackage oldPkg);
 
     /**
+     * Callback when a package has been installed for certain users.
+     *
+     * @param pkg the installed package
+     * @param grantedPermissions the permissions to be granted
+     * @param allowlistedRestrictedPermissions the restricted permissions to be allowlisted
+     * @param autoRevokePermissionsMode the auto revoke permissions mode for this package
+     * @param userId the user ID this package is installed for
+     */
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    public abstract void onPackageInstalled(@NonNull AndroidPackage pkg,
+            @NonNull List<String> grantedPermissions,
+            @NonNull List<String> allowlistedRestrictedPermissions,
+            int autoRevokePermissionsMode, @UserIdInt int userId);
+
+    /**
      * Callback when a package has been removed.
      *
      * @param pkg the removed package
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index cc36935..9026262 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -127,9 +127,11 @@
                 final boolean isWhiteListed;
                 boolean shouldApplyRestriction;
                 final int targetSDK;
+                final boolean hasLegacyExternalStorage;
                 final boolean hasRequestedLegacyExternalStorage;
-                final boolean shouldPreserveLegacyExternalStorage;
+                final boolean hasRequestedPreserveLegacyExternalStorage;
                 final boolean hasWriteMediaStorageGrantedForUid;
+                final boolean isForcedScopedStorage;
 
                 if (appInfo != null) {
                     PackageManager pm = context.getPackageManager();
@@ -137,27 +139,27 @@
                             LocalServices.getService(StorageManagerInternal.class);
                     int flags = pm.getPermissionFlags(permission, appInfo.packageName, user);
                     isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+                    hasLegacyExternalStorage = smInternal.hasLegacyExternalStorage(appInfo.uid);
                     hasRequestedLegacyExternalStorage = hasUidRequestedLegacyExternalStorage(
                             appInfo.uid, context);
                     hasWriteMediaStorageGrantedForUid = hasWriteMediaStorageGrantedForUid(
                             appInfo.uid, context);
-                    shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage()
-                            && smInternal.hasLegacyExternalStorage(appInfo.uid);
+                    hasRequestedPreserveLegacyExternalStorage =
+                            pkg.hasPreserveLegacyExternalStorage();
                     targetSDK = getMinimumTargetSDK(context, appInfo, user);
 
-                    shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
-                            || (targetSDK > Build.VERSION_CODES.Q
-                            && !shouldPreserveLegacyExternalStorage)
-                            // If the device is configured to force this app into scoped storage,
-                            // then we should apply the restriction
-                            || sForcedScopedStorageAppWhitelist.contains(appInfo.packageName);
+                    shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+                    isForcedScopedStorage = sForcedScopedStorageAppWhitelist
+                            .contains(appInfo.packageName);
                 } else {
                     isWhiteListed = false;
                     shouldApplyRestriction = false;
                     targetSDK = 0;
+                    hasLegacyExternalStorage = false;
                     hasRequestedLegacyExternalStorage = false;
-                    shouldPreserveLegacyExternalStorage = false;
+                    hasRequestedPreserveLegacyExternalStorage = false;
                     hasWriteMediaStorageGrantedForUid = false;
+                    isForcedScopedStorage = false;
                 }
 
                 // We have a check in PermissionPolicyService.PermissionToOpSynchroniser.setUidMode
@@ -175,14 +177,53 @@
                     }
                     @Override
                     public boolean mayAllowExtraAppOp() {
-                        return !shouldApplyRestriction
-                                && (hasRequestedLegacyExternalStorage
-                                        || hasWriteMediaStorageGrantedForUid
-                                        || shouldPreserveLegacyExternalStorage);
+                        // The only way to get LEGACY_STORAGE (if you didn't already have it)
+                        // is that all of the following must be true:
+                        // 1. The flag shouldn't be restricted
+                        if (shouldApplyRestriction) {
+                            return false;
+                        }
+
+                        // 2. The app shouldn't be in sForcedScopedStorageAppWhitelist
+                        if (isForcedScopedStorage) {
+                            return false;
+                        }
+
+                        // 3. The app has WRITE_MEDIA_STORAGE, OR
+                        //      the app already has legacy external storage or requested it,
+                        //      and is < R.
+                        return hasWriteMediaStorageGrantedForUid
+                                || ((hasLegacyExternalStorage || hasRequestedLegacyExternalStorage)
+                                    && targetSDK < Build.VERSION_CODES.R);
                     }
                     @Override
                     public boolean mayDenyExtraAppOpIfGranted() {
-                        return shouldApplyRestriction;
+                        // If you're an app targeting < R, you can keep the app op for
+                        // as long as you meet the conditions required to acquire it.
+                        if (targetSDK < Build.VERSION_CODES.R) {
+                            return !mayAllowExtraAppOp();
+                        }
+
+                        // For an app targeting R, the only way to lose LEGACY_STORAGE if you
+                        // already had it is in one or more of the following conditions:
+                        // 1. The flag became restricted
+                        if (shouldApplyRestriction) {
+                            return true;
+                        }
+
+                        // The package is now a part of the forced scoped storage whitelist
+                        if (isForcedScopedStorage) {
+                            return true;
+                        }
+
+                        // The package doesn't have WRITE_MEDIA_STORAGE,
+                        // AND didn't request legacy storage to be preserved
+                        if (!hasWriteMediaStorageGrantedForUid
+                                && !hasRequestedPreserveLegacyExternalStorage) {
+                            return true;
+                        }
+
+                        return false;
                     }
                 };
             }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index dd287ca..1e4e0a6 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -224,10 +224,9 @@
         mFileUpdater = new FileUpdater(context);
         mBatterySavingStats = batterySavingStats;
 
+        // TODO(79580230): remove plugin code and maybe screen on/off listeners?
         // Initialize plugins.
-        mPlugins = new Plugin[] {
-                new BatterySaverLocationPlugin(mContext)
-        };
+        mPlugins = new Plugin[0];
         PowerManager.invalidatePowerSaveModeCaches();
     }
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
deleted file mode 100644
index a77d133..0000000
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.power.batterysaver;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.util.Slog;
-
-import com.android.server.power.batterysaver.BatterySaverController.Plugin;
-
-public class BatterySaverLocationPlugin implements Plugin {
-    private static final String TAG = "BatterySaverLocationPlugin";
-
-    private static final boolean DEBUG = BatterySaverController.DEBUG;
-
-    private final Context mContext;
-
-    public BatterySaverLocationPlugin(Context context) {
-        mContext = context;
-    }
-
-    @Override
-    public void onBatterySaverChanged(BatterySaverController caller) {
-        if (DEBUG) {
-            Slog.d(TAG, "onBatterySaverChanged");
-        }
-        updateLocationState(caller);
-    }
-
-    @Override
-    public void onSystemReady(BatterySaverController caller) {
-        if (DEBUG) {
-            Slog.d(TAG, "onSystemReady");
-        }
-        updateLocationState(caller);
-    }
-
-    private void updateLocationState(BatterySaverController caller) {
-        final boolean kill =
-                (caller.getBatterySaverPolicy().getGpsMode()
-                        == PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF)
-                        && !caller.isInteractive();
-
-        if (DEBUG) {
-            Slog.d(TAG, "Battery saver " + (kill ? "stopping" : "restoring") + " location.");
-        }
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Global.LOCATION_GLOBAL_KILL_SWITCH, kill ? 1 : 0);
-    }
-}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 9829357..c9595c2 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -177,8 +177,28 @@
             // filename, so any files that don't match the current version number can be deleted.
             File[] files = mDataStorageDir.listFiles();
             for (int i = 0; i < files.length; i++) {
-                if (!files[i].getName().matches(dataStorageFilename + "(.*)")) {
-                    files[i].delete();
+                // Meter and model files are stored in the same directory.
+                //
+                // The format of filenames on disk is:
+                //    log.powerstats.meter.version.timestamp
+                //    log.powerstats.model.version.timestamp
+                //
+                // The format of dataStorageFilenames is:
+                //    log.powerstats.meter.version
+                //    log.powerstats.model.version
+                //
+                // A PowerStatsDataStorage object is created for meter and model data.  Strip off
+                // the version and check that the current file we're checking starts with the stem
+                // (log.powerstats.meter or log.powerstats.model). If the stem matches and the
+                // version number is different, delete the old file.
+                int versionDot = dataStorageFilename.lastIndexOf('.');
+                String beforeVersionDot = dataStorageFilename.substring(0, versionDot);
+                // Check that the stems match.
+                if (files[i].getName().startsWith(beforeVersionDot)) {
+                    // Check that the version number matches.  If not, delete the old file.
+                    if (!files[i].getName().startsWith(dataStorageFilename)) {
+                        files[i].delete();
+                    }
                 }
             }
 
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
index 18646b9..88e5f69 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
@@ -38,11 +38,41 @@
      */
     public interface IPowerStatsHALWrapper {
         /**
+         * Returns information related to all supported PowerEntity(s) for which state residency
+         * data is available.
+         *
+         * A PowerEntity is defined as a platform subsystem, peripheral, or power domain that
+         * impacts the total device power consumption.
+         *
+         * @return List of information on each PowerEntity.
+         */
+        android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo();
+
+        /**
+         * Reports the accumulated state residency for each requested PowerEntity.
+         *
+         * 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.
+         *
+         * Data is accumulated starting at device boot.
+         *
+         * @param powerEntityIds List of IDs of PowerEntities for which data is requested.  Passing
+         *                       an empty list will return state residency for all available
+         *                       PowerEntities.  ID of each PowerEntity is contained in
+         *                       PowerEntityInfo.
+         *
+         * @return StateResidency since boot for each requested PowerEntity
+         */
+        android.hardware.power.stats.StateResidencyResult[] getStateResidency(int[] powerEntityIds);
+
+        /**
          * Returns the energy consumer IDs for all available energy consumers (power models) on the
-         *         device.  Examples of subsystems for which energy consumer results (power models)
-         *         may be available are GPS, display, wifi, etc.  The default list of energy
-         *         consumers can be found in the PowerStats HAL definition (EnergyConsumerId.aidl).
-         *         The availability of energy consumer IDs is hardware dependent.
+         * device.  Examples of subsystems for which energy consumer results (power models) may be
+         * available are GPS, display, wifi, etc.  The default list of energy consumers can be
+         * found in the PowerStats HAL definition (EnergyConsumerId.aidl).  The availability of
+         * energy consumer IDs is hardware dependent.
          *
          * @return List of EnergyConsumerIds all available energy consumers.
          */
@@ -50,14 +80,19 @@
 
         /**
          * Returns the energy consumer result for all available energy consumers (power models).
-         *         Available consumers can be retrieved by calling getEnergyConsumerInfo().  The
-         *         subsystem corresponding to the energy consumer result is defined by the energy
-         *         consumer ID.
+         * Available consumers can be retrieved by calling getEnergyConsumerInfo().  The subsystem
+         * corresponding to the energy consumer result is defined by the energy consumer ID.
+         *
+         * @param energyConsumerIds Array of energy consumer IDs for which energy consumed is being
+         *                          requested.  Energy consumers available on the device can be
+         *                          queried by calling getEnergyConsumerInfo().  Passing an empty
+         *                          array will return results for all energy consumers.
          *
          * @return List of EnergyConsumerResult objects containing energy consumer results for all
          *         available energy consumers (power models).
          */
-        android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed();
+        android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
+                int[] energyConsumerIds);
 
         /**
          * Returns channel info for all available energy meters.
@@ -69,17 +104,21 @@
 
         /**
          * Returns energy measurements for all available energy meters.  Available channels can be
-         *         retrieved by calling getEnergyMeterInfo().  Energy measurements and channel info
-         *         can be linked through the channelId field.
+         * retrieved by calling getEnergyMeterInfo().  Energy measurements and channel info can be
+         * linked through the channelId field.
+         *
+         * @param channelIds Array of channel IDs for which energy measurements are being requested.
+         *                   Channel IDs available on the device can be queried by calling
+         *                   getEnergyMeterInfo().  Passing an empty array will return energy
+         *                   measurements for all channels.
          *
          * @return List of EnergyMeasurement objects containing energy measurements for all
          *         available energy meters.
          */
-        android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters();
+        android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(int[] channelIds);
 
         /**
-         * Returns boolean indicating if connection to power stats HAL was
-         *         established.
+         * Returns boolean indicating if connection to power stats HAL was established.
          *
          * @return true if connection to power stats HAL was correctly established.
          */
@@ -95,6 +134,38 @@
         private static Supplier<IPowerStats> sVintfPowerStats;
 
         @Override
+        public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
+            android.hardware.power.stats.PowerEntityInfo[] powerEntityInfoHAL = null;
+
+            if (sVintfPowerStats != null) {
+                try {
+                    powerEntityInfoHAL = sVintfPowerStats.get().getPowerEntityInfo();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to get power entity info from PowerStats HAL");
+                }
+            }
+
+            return powerEntityInfoHAL;
+        }
+
+        @Override
+        public android.hardware.power.stats.StateResidencyResult[] getStateResidency(
+                int[] powerEntityIds) {
+            android.hardware.power.stats.StateResidencyResult[] stateResidencyResultHAL = null;
+
+            if (sVintfPowerStats != null) {
+                try {
+                    stateResidencyResultHAL =
+                        sVintfPowerStats.get().getStateResidency(powerEntityIds);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to get state residency from PowerStats HAL");
+                }
+            }
+
+            return stateResidencyResultHAL;
+        }
+
+        @Override
         public int[] getEnergyConsumerInfo() {
             int[] energyConsumerInfoHAL = null;
 
@@ -110,13 +181,14 @@
         }
 
         @Override
-        public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed() {
+        public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
+                int[] energyConsumerIds) {
             android.hardware.power.stats.EnergyConsumerResult[] energyConsumedHAL = null;
 
             if (sVintfPowerStats != null) {
                 try {
                     energyConsumedHAL =
-                        sVintfPowerStats.get().getEnergyConsumed(new int[0]);
+                        sVintfPowerStats.get().getEnergyConsumed(energyConsumerIds);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to get energy consumer results from PowerStats HAL");
                 }
@@ -141,13 +213,13 @@
         }
 
         @Override
-        public android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters() {
+        public android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(int[] channelIds) {
             android.hardware.power.stats.EnergyMeasurement[] energyMeasurementHAL = null;
 
             if (sVintfPowerStats != null) {
                 try {
                     energyMeasurementHAL =
-                        sVintfPowerStats.get().readEnergyMeters(new int[0]);
+                        sVintfPowerStats.get().readEnergyMeters(channelIds);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to get energy measurements from PowerStats HAL");
                 }
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index f5131c4..409cd82 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -61,14 +61,15 @@
                 if (DEBUG) Slog.d(TAG, "Logging to data storage");
 
                 // Log power meter data.
-                EnergyMeasurement[] energyMeasurements = mPowerStatsHALWrapper.readEnergyMeters();
+                EnergyMeasurement[] energyMeasurements =
+                    mPowerStatsHALWrapper.readEnergyMeters(new int[0]);
                 mPowerStatsMeterStorage.write(
                         EnergyMeasurementUtils.getProtoBytes(energyMeasurements));
                 if (DEBUG) EnergyMeasurementUtils.print(energyMeasurements);
 
                 // Log power model data.
                 EnergyConsumerResult[] energyConsumerResults =
-                    mPowerStatsHALWrapper.getEnergyConsumed();
+                    mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
                 mPowerStatsModelStorage.write(
                         EnergyConsumerResultUtils.getProtoBytes(energyConsumerResults));
                 if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResults);
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index bf3919e..1150d4b 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.power.stats.ChannelInfo;
+import android.hardware.power.stats.PowerEntityInfo;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -31,6 +32,7 @@
 import com.android.server.powerstats.PowerStatsHALWrapper.PowerStatsHALWrapperImpl;
 import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils;
 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils;
+import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -110,6 +112,10 @@
                         mPowerStatsLogger.writeMeterDataToFile(fd);
                     }
                 } else if (args.length == 0) {
+                    pw.println("PowerStatsService dumpsys: available PowerEntityInfos");
+                    PowerEntityInfo[] powerEntityInfo = mPowerStatsHALWrapper.getPowerEntityInfo();
+                    PowerEntityInfoUtils.dumpsys(powerEntityInfo, pw);
+
                     pw.println("PowerStatsService dumpsys: available ChannelInfos");
                     ChannelInfo[] channelInfo = mPowerStatsHALWrapper.getEnergyMeterInfo();
                     ChannelInfoUtils.dumpsys(channelInfo, pw);
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 43afeed..5a4256a 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -19,6 +19,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.util.Slog;
 import android.util.proto.ProtoInputStream;
 import android.util.proto.ProtoOutputStream;
@@ -42,6 +44,48 @@
 public class ProtoStreamUtils {
     private static final String TAG = ProtoStreamUtils.class.getSimpleName();
 
+    static class PowerEntityInfoUtils {
+        public static void print(PowerEntityInfo[] powerEntityInfo) {
+            for (int i = 0; i < powerEntityInfo.length; i++) {
+                Slog.d(TAG, "PowerEntityId: " + powerEntityInfo[i].powerEntityId
+                        + ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
+                for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+                    Slog.d(TAG, "  StateId: " + powerEntityInfo[i].states[j].stateId
+                            + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+                }
+            }
+        }
+
+        public static void dumpsys(PowerEntityInfo[] powerEntityInfo, PrintWriter pw) {
+            for (int i = 0; i < powerEntityInfo.length; i++) {
+                pw.println("PowerEntityId: " + powerEntityInfo[i].powerEntityId
+                        + ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
+                for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+                    pw.println("  StateId: " + powerEntityInfo[i].states[j].stateId
+                            + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+                }
+            }
+        }
+    }
+
+    static class StateResidencyResultUtils {
+        public static void print(StateResidencyResult[] stateResidencyResult) {
+            for (int i = 0; i < stateResidencyResult.length; i++) {
+                Slog.d(TAG, "PowerEntityId: " + stateResidencyResult[i].powerEntityId);
+                for (int j = 0; j < stateResidencyResult[i].stateResidencyData.length; j++) {
+                    Slog.d(TAG, "  StateId: "
+                            + stateResidencyResult[i].stateResidencyData[j].stateId
+                            + ", TotalTimeInStateMs: "
+                            + stateResidencyResult[i].stateResidencyData[j].totalTimeInStateMs
+                            + ", TotalStateEntryCount: "
+                            + stateResidencyResult[i].stateResidencyData[j].totalStateEntryCount
+                            + ", LastEntryTimestampMs: "
+                            + stateResidencyResult[i].stateResidencyData[j].lastEntryTimestampMs);
+                }
+            }
+        }
+    }
+
     static class ChannelInfoUtils {
         public static void packProtoMessage(ChannelInfo[] channelInfo, ProtoOutputStream pos) {
             long token;
@@ -57,15 +101,15 @@
 
         public static void print(ChannelInfo[] channelInfo) {
             for (int i = 0; i < channelInfo.length; i++) {
-                Slog.d(TAG, "ChannelId = " + channelInfo[i].channelId
-                        + ", ChannelName = " + channelInfo[i].channelName);
+                Slog.d(TAG, "ChannelId: " + channelInfo[i].channelId
+                        + ", ChannelName: " + channelInfo[i].channelName);
             }
         }
 
         public static void dumpsys(ChannelInfo[] channelInfo, PrintWriter pw) {
             for (int i = 0; i < channelInfo.length; i++) {
-                pw.println("ChannelId = " + channelInfo[i].channelId
-                        + ", ChannelName = " + channelInfo[i].channelName);
+                pw.println("ChannelId: " + channelInfo[i].channelId
+                        + ", ChannelName: " + channelInfo[i].channelName);
             }
         }
     }
@@ -157,9 +201,9 @@
 
         public static void print(EnergyMeasurement[] energyMeasurement) {
             for (int i = 0; i < energyMeasurement.length; i++) {
-                Slog.d(TAG, "ChannelId = " + energyMeasurement[i].channelId
-                        + ", Timestamp (ms) = " + energyMeasurement[i].timestampMs
-                        + ", Energy (uWs) = " + energyMeasurement[i].energyUWs);
+                Slog.d(TAG, "ChannelId: " + energyMeasurement[i].channelId
+                        + ", Timestamp (ms): " + energyMeasurement[i].timestampMs
+                        + ", Energy (uWs): " + energyMeasurement[i].energyUWs);
             }
         }
     }
@@ -177,13 +221,13 @@
 
         public static void print(int[] energyConsumerId) {
             for (int i = 0; i < energyConsumerId.length; i++) {
-                Slog.d(TAG, "EnergyConsumerId = " + energyConsumerId[i]);
+                Slog.d(TAG, "EnergyConsumerId: " + energyConsumerId[i]);
             }
         }
 
         public static void dumpsys(int[] energyConsumerId, PrintWriter pw) {
             for (int i = 0; i < energyConsumerId.length; i++) {
-                pw.println("EnergyConsumerId = " + energyConsumerId[i]);
+                pw.println("EnergyConsumerId: " + energyConsumerId[i]);
             }
         }
     }
@@ -278,9 +322,9 @@
 
         public static void print(EnergyConsumerResult[] energyConsumerResult) {
             for (int i = 0; i < energyConsumerResult.length; i++) {
-                Slog.d(TAG, "EnergyConsumerId = " + energyConsumerResult[i].energyConsumerId
-                        + ", Timestamp (ms) = " + energyConsumerResult[i].timestampMs
-                        + ", Energy (uWs) = " + energyConsumerResult[i].energyUWs);
+                Slog.d(TAG, "EnergyConsumerId: " + energyConsumerResult[i].energyConsumerId
+                        + ", Timestamp (ms): " + energyConsumerResult[i].timestampMs
+                        + ", Energy (uWs): " + energyConsumerResult[i].energyUWs);
             }
         }
     }
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index b33dc8f..7751397 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -28,6 +28,7 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -391,8 +392,7 @@
     private void readLegacyFileLocked() {
         File file = getFile(mUserId);
         try (FileInputStream in = new AtomicFile(file).openRead()) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(in, null);
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
             parseXmlLocked(parser);
             Slog.i(LOG_TAG, "Read roles.xml successfully");
         } catch (FileNotFoundException e) {
@@ -402,7 +402,7 @@
         }
     }
 
-    private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException,
+    private void parseXmlLocked(@NonNull TypedXmlPullParser parser) throws IOException,
             XmlPullParserException {
         int type;
         int depth;
@@ -421,9 +421,9 @@
         Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml");
     }
 
-    private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
+    private void parseRolesLocked(@NonNull TypedXmlPullParser parser) throws IOException,
             XmlPullParserException {
-        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
+        mVersion = parser.getAttributeInt(null, ATTRIBUTE_VERSION);
         mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
         mRoles.clear();
 
@@ -445,7 +445,7 @@
     }
 
     @NonNull
-    private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
+    private ArraySet<String> parseRoleHoldersLocked(@NonNull TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         ArraySet<String> roleHolders = new ArraySet<>();
 
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 2d51cf9..63ed416 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -141,11 +141,17 @@
 
     /**
      * The current state of the rollback.
-     * ENABLING, AVAILABLE, or COMMITTED.
+     * ENABLING, AVAILABLE, DELETED, or COMMITTED.
      */
     private @RollbackState int mState;
 
     /**
+     * The detailed description of the current state. For a DELETED state, it describes
+     * the reason why the rollback is deleted.
+     */
+    private @NonNull String mStateDescription = "";
+
+    /**
      * True if we are expecting the package manager to call restoreUserData
      * for this rollback because it has just been committed but the rollback
      * has not yet been fully applied.
@@ -231,7 +237,7 @@
      * Constructs a pre-populated Rollback instance.
      */
     Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
-            @RollbackState int state, boolean restoreUserDataInProgress,
+            @RollbackState int state, String stateDescription, boolean restoreUserDataInProgress,
             int userId, String installerPackageName, SparseIntArray extensionVersions) {
         this.info = info;
         mUserId = userId;
@@ -240,6 +246,7 @@
         mTimestamp = timestamp;
         mStagedSessionId = stagedSessionId;
         mState = state;
+        mStateDescription = stateDescription;
         mRestoreUserDataInProgress = restoreUserDataInProgress;
         mExtensionVersions = Objects.requireNonNull(extensionVersions);
         // TODO(b/120200473): Include this field during persistence. This field will be used to
@@ -478,7 +485,7 @@
             Slog.w(TAG, "Cannot make deleted rollback available.");
             return;
         }
-        mState = ROLLBACK_STATE_AVAILABLE;
+        setState(ROLLBACK_STATE_AVAILABLE, "");
         mTimestamp = Instant.now();
         RollbackStore.saveRollback(this);
     }
@@ -598,7 +605,7 @@
                         // Why would we expect commit not to fail again?
                         // TODO: Could this cause a rollback to be resurrected
                         // if it should otherwise have expired by now?
-                        mState = ROLLBACK_STATE_AVAILABLE;
+                        setState(ROLLBACK_STATE_AVAILABLE, "Commit failed");
                         mRestoreUserDataInProgress = false;
                         info.setCommittedSessionId(-1);
                         sendFailure(context, statusReceiver,
@@ -642,7 +649,7 @@
             };
 
             final LocalIntentReceiver receiver = new LocalIntentReceiver(onResult);
-            mState = ROLLBACK_STATE_COMMITTED;
+            setState(ROLLBACK_STATE_COMMITTED, "");
             info.setCommittedSessionId(parentSessionId);
             mRestoreUserDataInProgress = true;
             parentSession.commit(receiver.getIntentSender());
@@ -691,7 +698,7 @@
      * Deletes app data snapshots associated with this rollback, and moves to the DELETED state.
      */
     @WorkerThread
-    void delete(AppDataRollbackHelper dataHelper) {
+    void delete(AppDataRollbackHelper dataHelper, @NonNull String reason) {
         assertInWorkerThread();
         boolean containsApex = false;
         Set<Integer> apexUsers = new ArraySet<>();
@@ -717,7 +724,7 @@
         }
 
         RollbackStore.deleteRollback(this);
-        mState = ROLLBACK_STATE_DELETED;
+        setState(ROLLBACK_STATE_DELETED, reason);
     }
 
     /**
@@ -847,6 +854,7 @@
             case Rollback.ROLLBACK_STATE_ENABLING: return "enabling";
             case Rollback.ROLLBACK_STATE_AVAILABLE: return "available";
             case Rollback.ROLLBACK_STATE_COMMITTED: return "committed";
+            case Rollback.ROLLBACK_STATE_DELETED: return "deleted";
         }
         throw new AssertionError("Invalid rollback state: " + state);
     }
@@ -858,6 +866,7 @@
             case "enabling": return Rollback.ROLLBACK_STATE_ENABLING;
             case "available": return Rollback.ROLLBACK_STATE_AVAILABLE;
             case "committed": return Rollback.ROLLBACK_STATE_COMMITTED;
+            case "deleted": return Rollback.ROLLBACK_STATE_DELETED;
         }
         throw new ParseException("Invalid rollback state: " + state, 0);
     }
@@ -926,6 +935,7 @@
         ipw.println(info.getRollbackId() + ":");
         ipw.increaseIndent();
         ipw.println("-state: " + getStateAsString());
+        ipw.println("-stateDescription: " + mStateDescription);
         ipw.println("-timestamp: " + getTimestamp());
         if (getStagedSessionId() != -1) {
             ipw.println("-stagedSessionId: " + getStagedSessionId());
@@ -955,4 +965,17 @@
         }
         ipw.decreaseIndent();
     }
+
+    @WorkerThread
+    String getStateDescription() {
+        assertInWorkerThread();
+        return mStateDescription;
+    }
+
+    @VisibleForTesting
+    void setState(@RollbackState int state, String description) {
+        assertInWorkerThread();
+        mState = state;
+        mStateDescription = description;
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index b34d46f..192a003 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -179,7 +179,9 @@
         mInstaller = new Installer(mContext);
         mInstaller.onStart();
 
-        mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
+        mRollbackStore = new RollbackStore(
+                new File(Environment.getDataDirectory(), "rollback"),
+                new File(Environment.getDataDirectory(), "rollback-history"));
 
         mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
         mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
@@ -201,7 +203,7 @@
             } else {
                 // Delete rollbacks when build fingerprint has changed.
                 for (Rollback rollback : mRollbacks) {
-                    rollback.delete(mAppDataRollbackHelper);
+                    deleteRollback(rollback, "Fingerprint changed");
                 }
                 mRollbacks.clear();
             }
@@ -271,7 +273,7 @@
                     Rollback rollback = getRollbackForSession(sessionId);
                     if (rollback != null && rollback.isEnabling()) {
                         mRollbacks.remove(rollback);
-                        rollback.delete(mAppDataRollbackHelper);
+                        deleteRollback(rollback, "Rollback canceled");
                     }
                 }
             }
@@ -477,14 +479,14 @@
     }
 
     @WorkerThread
-    private void expireRollbackForPackageInternal(String packageName) {
+    private void expireRollbackForPackageInternal(String packageName, String reason) {
         assertInWorkerThread();
         Iterator<Rollback> iter = mRollbacks.iterator();
         while (iter.hasNext()) {
             Rollback rollback = iter.next();
             if (rollback.includesPackage(packageName)) {
                 iter.remove();
-                rollback.delete(mAppDataRollbackHelper);
+                deleteRollback(rollback, reason);
             }
         }
     }
@@ -496,7 +498,7 @@
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.TEST_MANAGE_ROLLBACKS,
                 "expireRollbackForPackage");
-        awaitResult(() -> expireRollbackForPackageInternal(packageName));
+        awaitResult(() -> expireRollbackForPackageInternal(packageName, "Expired by API"));
     }
 
     @ExtThread
@@ -612,7 +614,8 @@
                         .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
                 if (session == null || session.isStagedSessionFailed()) {
                     iter.remove();
-                    rollback.delete(mAppDataRollbackHelper);
+                    deleteRollback(rollback,
+                            "Session " + session.getSessionId() + " not existed or failed");
                     continue;
                 }
 
@@ -666,7 +669,7 @@
                     && rollback.includesPackageWithDifferentVersion(packageName,
                     installedVersion)) {
                 iter.remove();
-                rollback.delete(mAppDataRollbackHelper);
+                deleteRollback(rollback, "Package " + packageName + " replaced");
             }
         }
     }
@@ -678,7 +681,7 @@
     @WorkerThread
     private void onPackageFullyRemoved(String packageName) {
         assertInWorkerThread();
-        expireRollbackForPackageInternal(packageName);
+        expireRollbackForPackageInternal(packageName, "Package " + packageName + " removed");
     }
 
     /**
@@ -713,14 +716,14 @@
         Iterator<Rollback> iter = mRollbacks.iterator();
         while (iter.hasNext()) {
             Rollback rollback = iter.next();
-            if (!rollback.isAvailable()) {
+            if (!rollback.isAvailable() && !rollback.isCommitted()) {
                 continue;
             }
             Instant rollbackTimestamp = rollback.getTimestamp();
             if (!now.isBefore(rollbackTimestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
                 Slog.i(TAG, "runExpiration id=" + rollback.info.getRollbackId());
                 iter.remove();
-                rollback.delete(mAppDataRollbackHelper);
+                deleteRollback(rollback, "Expired by timeout");
             } else if (oldest == null || oldest.isAfter(rollbackTimestamp)) {
                 oldest = rollbackTimestamp;
             }
@@ -1132,7 +1135,7 @@
                     Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
                             + " for failed session id=" + sessionId);
                     mRollbacks.remove(rollback);
-                    rollback.delete(mAppDataRollbackHelper);
+                    deleteRollback(rollback, "Session " + sessionId + " failed");
                 }
             }
         }
@@ -1159,7 +1162,7 @@
         if (!rollback.allPackagesEnabled()) {
             Slog.e(TAG, "Failed to enable rollback for all packages in session.");
             mRollbacks.remove(rollback);
-            rollback.delete(mAppDataRollbackHelper);
+            deleteRollback(rollback, "Failed to enable rollback for all packages in session");
             return false;
         }
 
@@ -1240,6 +1243,18 @@
                 rollback.dump(ipw);
             }
             ipw.println();
+
+            List<Rollback> historicalRollbacks = mRollbackStore.loadHistorialRollbacks();
+            if (!historicalRollbacks.isEmpty()) {
+                ipw.println("Historical rollbacks:");
+                ipw.increaseIndent();
+                for (Rollback rollback : historicalRollbacks) {
+                    rollback.dump(ipw);
+                }
+                ipw.decreaseIndent();
+                ipw.println();
+            }
+
             PackageWatchdog.getInstance(mContext).dump(ipw);
         });
     }
@@ -1329,4 +1344,11 @@
         }
         return null;
     }
+
+    @WorkerThread
+    private void deleteRollback(Rollback rollback, String reason) {
+        assertInWorkerThread();
+        rollback.delete(mAppDataRollbackHelper, reason);
+        mRollbackStore.saveRollbackToHistory(rollback);
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 2ee87e6..35c9f9a 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -69,18 +69,20 @@
     // * XXX, YYY are the rollbackIds for the corresponding rollbacks.
     // * rollback.json contains all relevant metadata for the rollback.
     private final File mRollbackDataDir;
+    private final File mRollbackHistoryDir;
 
-    RollbackStore(File rollbackDataDir) {
+    RollbackStore(File rollbackDataDir, File rollbackHistoryDir) {
         mRollbackDataDir = rollbackDataDir;
+        mRollbackHistoryDir = rollbackHistoryDir;
     }
 
     /**
      * Reads the rollbacks from persistent storage.
      */
-    List<Rollback> loadRollbacks() {
+    private static List<Rollback> loadRollbacks(File rollbackDataDir) {
         List<Rollback> rollbacks = new ArrayList<>();
-        mRollbackDataDir.mkdirs();
-        for (File rollbackDir : mRollbackDataDir.listFiles()) {
+        rollbackDataDir.mkdirs();
+        for (File rollbackDir : rollbackDataDir.listFiles()) {
             if (rollbackDir.isDirectory()) {
                 try {
                     rollbacks.add(loadRollback(rollbackDir));
@@ -93,6 +95,14 @@
         return rollbacks;
     }
 
+    List<Rollback> loadRollbacks() {
+        return loadRollbacks(mRollbackDataDir);
+    }
+
+    List<Rollback> loadHistorialRollbacks() {
+        return loadRollbacks(mRollbackHistoryDir);
+    }
+
     /**
      * Converts a {@code JSONArray} of integers to a {@code List<Integer>}.
      */
@@ -258,15 +268,17 @@
     /**
      * Saves the given rollback to persistent storage.
      */
-    static void saveRollback(Rollback rollback) {
+    private static void saveRollback(Rollback rollback, File backDir) {
         FileOutputStream fos = null;
-        AtomicFile file = new AtomicFile(new File(rollback.getBackupDir(), "rollback.json"));
+        AtomicFile file = new AtomicFile(new File(backDir, "rollback.json"));
         try {
+            backDir.mkdirs();
             JSONObject dataJson = new JSONObject();
             dataJson.put("info", rollbackInfoToJson(rollback.info));
             dataJson.put("timestamp", rollback.getTimestamp().toString());
             dataJson.put("stagedSessionId", rollback.getStagedSessionId());
             dataJson.put("state", rollback.getStateAsString());
+            dataJson.put("stateDescription", rollback.getStateDescription());
             dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress());
             dataJson.put("userId", rollback.getUserId());
             dataJson.putOpt("installerPackageName", rollback.getInstallerPackageName());
@@ -286,6 +298,22 @@
         }
     }
 
+    static void saveRollback(Rollback rollback) {
+        saveRollback(rollback, rollback.getBackupDir());
+    }
+
+    /**
+     * Saves the rollback to $mRollbackHistoryDir/ROLLBACKID-HEX for debugging purpose.
+     */
+    void saveRollbackToHistory(Rollback rollback) {
+        // The same id might be allocated to different historical rollbacks.
+        // Let's add a suffix to avoid naming collision.
+        String suffix = Long.toHexString(rollback.getTimestamp().getEpochSecond());
+        String dirName = Integer.toString(rollback.info.getRollbackId());
+        File backupDir = new File(mRollbackHistoryDir, dirName + "-" + suffix);
+        saveRollback(rollback, backupDir);
+    }
+
     /**
      * Removes all persistent storage associated with the given rollback.
      */
@@ -318,6 +346,7 @@
                 Instant.parse(dataJson.getString("timestamp")),
                 dataJson.getInt("stagedSessionId"),
                 rollbackStateFromString(dataJson.getString("state")),
+                dataJson.optString("stateDescription"),
                 dataJson.getBoolean("restoreUserDataInProgress"),
                 dataJson.optInt("userId", UserHandle.SYSTEM.getIdentifier()),
                 dataJson.optString("installerPackageName", ""),
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index d2614e4..4f3101d 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -51,13 +51,10 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.Preconditions;
 import com.android.server.pm.Installer;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -65,7 +62,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -319,12 +315,12 @@
     }
 
     @VisibleForTesting
-    static void saveToXml(XmlSerializer out,
+    static void saveToXml(TypedXmlSerializer out,
             List<CacheQuotaHint> requests, long bytesWhenCalculated) throws IOException {
         out.startDocument(null, true);
         out.startTag(null, CACHE_INFO_TAG);
         int requestSize = requests.size();
-        out.attribute(null, ATTR_PREVIOUS_BYTES, Long.toString(bytesWhenCalculated));
+        out.attributeLong(null, ATTR_PREVIOUS_BYTES, bytesWhenCalculated);
 
         for (int i = 0; i < requestSize; i++) {
             CacheQuotaHint request = requests.get(i);
@@ -333,8 +329,8 @@
             if (uuid != null) {
                 out.attribute(null, ATTR_UUID, request.getVolumeUuid());
             }
-            out.attribute(null, ATTR_UID, Integer.toString(request.getUid()));
-            out.attribute(null, ATTR_QUOTA_IN_BYTES, Long.toString(request.getQuota()));
+            out.attributeInt(null, ATTR_UID, request.getUid());
+            out.attributeLong(null, ATTR_QUOTA_IN_BYTES, request.getQuota());
             out.endTag(null, TAG_QUOTA);
         }
         out.endTag(null, CACHE_INFO_TAG);
@@ -364,8 +360,7 @@
         final List<CacheQuotaHint> quotas = new ArrayList<>();
         long previousBytes;
         try {
-            previousBytes = Long.parseLong(parser.getAttributeValue(
-                    null, ATTR_PREVIOUS_BYTES));
+            previousBytes = parser.getAttributeLong(null, ATTR_PREVIOUS_BYTES);
         } catch (NumberFormatException e) {
             throw new IllegalStateException(
                     "Previous bytes formatted incorrectly; aborting quota read.");
@@ -389,14 +384,14 @@
     }
 
     @VisibleForTesting
-    static CacheQuotaHint getRequestFromXml(XmlPullParser parser) {
+    static CacheQuotaHint getRequestFromXml(TypedXmlPullParser parser) {
         try {
             String uuid = parser.getAttributeValue(null, ATTR_UUID);
-            int uid = Integer.parseInt(parser.getAttributeValue(null, ATTR_UID));
-            long bytes = Long.parseLong(parser.getAttributeValue(null, ATTR_QUOTA_IN_BYTES));
+            int uid = parser.getAttributeInt(null, ATTR_UID);
+            long bytes = parser.getAttributeLong(null, ATTR_QUOTA_IN_BYTES);
             return new CacheQuotaHint.Builder()
                     .setVolumeUuid(uuid).setUid(uid).setQuota(bytes).build();
-        } catch (NumberFormatException e) {
+        } catch (XmlPullParserException e) {
             Slog.e(TAG, "Invalid cache quota request, skipping.");
             return null;
         }
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index b79fc8d..af26289 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -23,6 +23,7 @@
 import static com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
 
 import android.annotation.MainThread;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
@@ -34,28 +35,27 @@
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelableException;
 import android.os.RemoteCallback;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.StorageVolume;
 import android.service.storage.ExternalStorageService;
 import android.service.storage.IExternalStorageService;
-import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 /**
  * Controls the lifecycle of the {@link ActiveConnection} to an {@link ExternalStorageService}
@@ -66,25 +66,20 @@
 
     private static final int DEFAULT_REMOTE_TIMEOUT_SECONDS = 20;
 
-    private final Object mLock = new Object();
+    private final Object mSessionsLock = new Object();
     private final Context mContext;
     private final int mUserId;
     private final StorageSessionController mSessionController;
     private final ActiveConnection mActiveConnection = new ActiveConnection();
-    private final boolean mIsDemoUser;
     @GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
-    @GuardedBy("mLock") @Nullable private HandlerThread mHandlerThread;
+    private final HandlerThread mHandlerThread;
 
     public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
         mContext = Objects.requireNonNull(context);
         mUserId = Preconditions.checkArgumentNonnegative(userId);
         mSessionController = controller;
-        mIsDemoUser = LocalServices.getService(UserManagerInternal.class)
-                .getUserInfo(userId).isDemo();
-        if (mIsDemoUser) {
-            mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
-            mHandlerThread.start();
-        }
+        mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
+        mHandlerThread.start();
     }
 
     /**
@@ -101,13 +96,12 @@
         Objects.requireNonNull(upperPath);
         Objects.requireNonNull(lowerPath);
 
-        prepareRemote();
-        synchronized (mLock) {
+        Session session = new Session(sessionId, upperPath, lowerPath);
+        synchronized (mSessionsLock) {
             Preconditions.checkArgument(!mSessions.containsKey(sessionId));
-            Session session = new Session(sessionId, upperPath, lowerPath);
             mSessions.put(sessionId, session);
-            mActiveConnection.startSessionLocked(session, pfd);
         }
+        mActiveConnection.startSession(session, pfd);
     }
 
     /**
@@ -121,10 +115,13 @@
         Objects.requireNonNull(sessionId);
         Objects.requireNonNull(vol);
 
-        prepareRemote();
-        synchronized (mLock) {
-            mActiveConnection.notifyVolumeStateChangedLocked(sessionId, vol);
+        synchronized (mSessionsLock) {
+            if (!mSessions.containsKey(sessionId)) {
+                Slog.i(TAG, "No session found for sessionId: " + sessionId);
+                return;
+            }
         }
+        mActiveConnection.notifyVolumeStateChanged(sessionId, vol);
     }
 
     /**
@@ -135,7 +132,7 @@
      * with {@link #waitForExit}.
      **/
     public Session removeSession(String sessionId) {
-        synchronized (mLock) {
+        synchronized (mSessionsLock) {
             return mSessions.remove(sessionId);
         }
     }
@@ -153,10 +150,7 @@
         }
 
         Slog.i(TAG, "Waiting for session end " + session + " ...");
-        prepareRemote();
-        synchronized (mLock) {
-            mActiveConnection.endSessionLocked(session);
-        }
+        mActiveConnection.endSession(session);
     }
 
     /** Restarts all available sessions for a user without blocking.
@@ -164,7 +158,7 @@
      * Any failures will be ignored.
      **/
     public void resetUserSessions() {
-        synchronized (mLock) {
+        synchronized (mSessionsLock) {
             if (mSessions.isEmpty()) {
                 // Nothing to reset if we have no sessions to restart; we typically
                 // hit this path if the user was consciously shut down.
@@ -179,7 +173,7 @@
      * Removes all sessions, without waiting.
      */
     public void removeAllSessions() {
-        synchronized (mLock) {
+        synchronized (mSessionsLock) {
             Slog.i(TAG, "Removing  " + mSessions.size() + " sessions for user: " + mUserId + "...");
             mSessions.clear();
         }
@@ -191,68 +185,54 @@
      */
     public void close() {
         mActiveConnection.close();
-        if (mIsDemoUser) {
-            mHandlerThread.quit();
-        }
+        mHandlerThread.quit();
     }
 
     /** Returns all created sessions. */
     public Set<String> getAllSessionIds() {
-        synchronized (mLock) {
+        synchronized (mSessionsLock) {
             return new HashSet<>(mSessions.keySet());
         }
     }
 
-    private void prepareRemote() throws ExternalStorageServiceException {
-        try {
-            waitForLatch(mActiveConnection.bind(), "remote_prepare_user " + mUserId);
-        } catch (IllegalStateException | TimeoutException e) {
-            throw new ExternalStorageServiceException("Failed to prepare remote", e);
-        }
-    }
-
-    private void waitForLatch(CountDownLatch latch, String reason) throws TimeoutException {
-        try {
-            if (!latch.await(DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
-                // TODO(b/140025078): Call ActivityManager ANR API?
-                Slog.wtf(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
-                throw new TimeoutException("Latch wait for " + reason + " elapsed");
-            }
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new IllegalStateException("Latch wait for " + reason + " interrupted");
-        }
+    @FunctionalInterface
+    interface AsyncStorageServiceCall {
+        void run(@NonNull IExternalStorageService service, RemoteCallback callback) throws
+                RemoteException;
     }
 
     private final class ActiveConnection implements AutoCloseable {
+        private final Object mLock = new Object();
+
         // Lifecycle connection to the external storage service, needed to unbind.
         @GuardedBy("mLock") @Nullable private ServiceConnection mServiceConnection;
-        // True if we are connecting, either bound or binding
-        // False && mRemote != null means we are connected
-        // False && mRemote == null means we are neither connecting nor connected
-        @GuardedBy("mLock") @Nullable private boolean mIsConnecting;
-        // Binder object representing the external storage service.
-        // Non-null indicates we are connected
-        @GuardedBy("mLock") @Nullable private IExternalStorageService mRemote;
-        // Exception, if any, thrown from #startSessionLocked or #endSessionLocked
-        // Local variables cannot be referenced from a lambda expression :( so we
-        // save the exception received in the callback here. Since we guard access
-        // (and clear the exception state) with the same lock which we hold during
-        // the entire transaction, there is no risk of race.
-        @GuardedBy("mLock") @Nullable private ParcelableException mLastException;
-        // Not guarded by any lock intentionally and non final because we cannot
-        // reset latches so need to create a new one after one use
-        private CountDownLatch mLatch;
+
+        // A future that holds the remote interface
+        @GuardedBy("mLock")
+        @Nullable private CompletableFuture<IExternalStorageService> mRemoteFuture;
+
+        // A list of outstanding futures for async calls, for which we are still waiting
+        // for a callback. Used to unblock waiters if the service dies.
+        @GuardedBy("mLock")
+        private ArrayList<CompletableFuture<Void>> mOutstandingOps = new ArrayList<>();
 
         @Override
         public void close() {
             ServiceConnection oldConnection = null;
             synchronized (mLock) {
                 Slog.i(TAG, "Closing connection for user " + mUserId);
-                mIsConnecting = false;
                 oldConnection = mServiceConnection;
                 mServiceConnection = null;
-                mRemote = null;
+                if (mRemoteFuture != null) {
+                    // Let folks who are waiting for the connection know it ain't gonna happen
+                    mRemoteFuture.cancel(true);
+                    mRemoteFuture = null;
+                }
+                // Let folks waiting for callbacks from the remote know it ain't gonna happen
+                for (CompletableFuture<Void> op : mOutstandingOps) {
+                    op.cancel(true);
+                }
+                mOutstandingOps.clear();
             }
 
             if (oldConnection != null) {
@@ -266,37 +246,37 @@
             }
         }
 
-        public boolean isActiveLocked(Session session) {
-            if (!session.isInitialisedLocked()) {
-                Slog.i(TAG, "Session not initialised " + session);
-                return false;
-            }
+        private void waitForAsync(AsyncStorageServiceCall asyncCall) throws Exception {
+            CompletableFuture<IExternalStorageService> serviceFuture = connectIfNeeded();
+            CompletableFuture<Void> opFuture = new CompletableFuture<>();
 
-            if (mRemote == null) {
-                throw new IllegalStateException("Valid session with inactive connection");
+            try {
+                synchronized (mLock) {
+                    mOutstandingOps.add(opFuture);
+                }
+                serviceFuture.thenCompose(service -> {
+                    try {
+                        asyncCall.run(service,
+                                new RemoteCallback(result -> setResult(result, opFuture)));
+                    } catch (RemoteException e) {
+                        opFuture.completeExceptionally(e);
+                    }
+
+                    return opFuture;
+                }).get(DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+            } finally {
+                synchronized (mLock) {
+                    mOutstandingOps.remove(opFuture);
+                }
             }
-            return true;
         }
 
-        public void startSessionLocked(Session session, ParcelFileDescriptor fd)
+        public void startSession(Session session, ParcelFileDescriptor fd)
                 throws ExternalStorageServiceException {
-            if (!isActiveLocked(session)) {
-                try {
-                    fd.close();
-                } catch (IOException e) {
-                    // ignore
-                }
-                return;
-            }
-
-            CountDownLatch latch = new CountDownLatch(1);
             try {
-                mRemote.startSession(session.sessionId,
+                waitForAsync((service, callback) -> service.startSession(session.sessionId,
                         FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE,
-                        fd, session.upperPath, session.lowerPath, new RemoteCallback(result ->
-                                setResultLocked(latch, result)));
-                waitForLatch(latch, "start_session " + session);
-                maybeThrowExceptionLocked();
+                        fd, session.upperPath, session.lowerPath, callback));
             } catch (Exception e) {
                 throw new ExternalStorageServiceException("Failed to start session: " + session, e);
             } finally {
@@ -308,73 +288,49 @@
             }
         }
 
-        public void endSessionLocked(Session session) throws ExternalStorageServiceException {
-            if (!isActiveLocked(session)) {
-                // Nothing to end, not started yet
-                return;
-            }
-
-            CountDownLatch latch = new CountDownLatch(1);
+        public void endSession(Session session) throws ExternalStorageServiceException {
             try {
-                mRemote.endSession(session.sessionId, new RemoteCallback(result ->
-                        setResultLocked(latch, result)));
-                waitForLatch(latch, "end_session " + session);
-                maybeThrowExceptionLocked();
+                waitForAsync((service, callback) ->
+                        service.endSession(session.sessionId, callback));
             } catch (Exception e) {
                 throw new ExternalStorageServiceException("Failed to end session: " + session, e);
             }
         }
 
-        public void notifyVolumeStateChangedLocked(String sessionId, StorageVolume vol) throws
+
+        public void notifyVolumeStateChanged(String sessionId, StorageVolume vol) throws
                 ExternalStorageServiceException {
-            CountDownLatch latch = new CountDownLatch(1);
             try {
-                mRemote.notifyVolumeStateChanged(sessionId, vol, new RemoteCallback(
-                        result -> setResultLocked(latch, result)));
-                waitForLatch(latch, "notify_volume_state_changed " + vol);
-                maybeThrowExceptionLocked();
+                waitForAsync((service, callback) ->
+                        service.notifyVolumeStateChanged(sessionId, vol, callback));
             } catch (Exception e) {
                 throw new ExternalStorageServiceException("Failed to notify volume state changed "
                         + "for vol : " + vol, e);
             }
         }
 
-        private void setResultLocked(CountDownLatch latch, Bundle result) {
-            mLastException = result.getParcelable(EXTRA_ERROR);
-            latch.countDown();
-        }
-
-        private void maybeThrowExceptionLocked() throws IOException {
-            if (mLastException != null) {
-                ParcelableException lastException = mLastException;
-                mLastException = null;
-                try {
-                    lastException.maybeRethrow(IOException.class);
-                } catch (IOException e) {
-                    throw e;
-                }
-                throw new RuntimeException(lastException);
+        private void setResult(Bundle result, CompletableFuture<Void> future) {
+            ParcelableException ex = result.getParcelable(EXTRA_ERROR);
+            if (ex != null) {
+                future.completeExceptionally(ex);
+            } else {
+                future.complete(null);
             }
         }
 
-        public CountDownLatch bind() throws ExternalStorageServiceException {
+        private CompletableFuture<IExternalStorageService> connectIfNeeded() throws
+                ExternalStorageServiceException {
             ComponentName name = mSessionController.getExternalStorageServiceComponentName();
             if (name == null) {
                 // Not ready to bind
                 throw new ExternalStorageServiceException(
                         "Not ready to bind to the ExternalStorageService for user " + mUserId);
             }
-
             synchronized (mLock) {
-                if (mRemote != null || mIsConnecting) {
-                    // Connected or connecting (bound or binding)
-                    // Will wait on a latch that will countdown when we connect, unless we are
-                    // connected and the latch has already countdown, yay!
-                    return mLatch;
-                } // else neither connected nor connecting
-
-                mLatch = new CountDownLatch(1);
-                mIsConnecting = true;
+                if (mRemoteFuture != null) {
+                    return mRemoteFuture;
+                }
+                CompletableFuture<IExternalStorageService> future = new CompletableFuture<>();
                 mServiceConnection = new ServiceConnection() {
                     @Override
                     public void onServiceConnected(ComponentName name, IBinder service) {
@@ -406,16 +362,9 @@
 
                     private void handleConnection(IBinder service) {
                         synchronized (mLock) {
-                            if (mIsConnecting) {
-                                mRemote = IExternalStorageService.Stub.asInterface(service);
-                                mIsConnecting = false;
-                                mLatch.countDown();
-                                // Separate thread so we don't block the main thead
-                                return;
-                            }
+                            future.complete(
+                                    IExternalStorageService.Stub.asInterface(service));
                         }
-                        Slog.wtf(TAG, "Connection closed to the ExternalStorageService for user "
-                                + mUserId);
                     }
 
                     private void handleDisconnection() {
@@ -429,32 +378,19 @@
                 };
 
                 Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
-                if (mIsDemoUser) {
-                    // Schedule on a worker thread for demo user to avoid deadlock
-                    if (mContext.bindServiceAsUser(new Intent().setComponent(name),
-                                    mServiceConnection,
-                                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
-                                    mHandlerThread.getThreadHandler(),
-                                    UserHandle.of(mUserId))) {
-                        Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
-                        return mLatch;
-                    } else {
-                        mIsConnecting = false;
-                        throw new ExternalStorageServiceException(
-                                "Failed to bind to the ExternalStorageService for user " + mUserId);
-                    }
+                // Schedule on a worker thread, because the system server main thread can be
+                // very busy early in boot.
+                if (mContext.bindServiceAsUser(new Intent().setComponent(name),
+                                mServiceConnection,
+                                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+                                mHandlerThread.getThreadHandler(),
+                                UserHandle.of(mUserId))) {
+                    Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+                    mRemoteFuture = future;
+                    return future;
                 } else {
-                    if (mContext.bindServiceAsUser(new Intent().setComponent(name),
-                                    mServiceConnection,
-                                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
-                                    UserHandle.of(mUserId))) {
-                        Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
-                        return mLatch;
-                    } else {
-                        mIsConnecting = false;
-                        throw new ExternalStorageServiceException(
-                                "Failed to bind to the ExternalStorageService for user " + mUserId);
-                    }
+                    throw new ExternalStorageServiceException(
+                            "Failed to bind to the ExternalStorageService for user " + mUserId);
                 }
             }
         }
@@ -476,10 +412,5 @@
             return "[SessionId: " + sessionId + ". UpperPath: " + upperPath + ". LowerPath: "
                     + lowerPath + "]";
         }
-
-        @GuardedBy("mLock")
-        public boolean isInitialisedLocked() {
-            return !TextUtils.isEmpty(upperPath) && !TextUtils.isEmpty(lowerPath);
-        }
     }
 }
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 59cebf7..7de0e87 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -71,9 +71,8 @@
     @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
 
     private static TimeDetectorService create(@NonNull Context context) {
-        TimeDetectorStrategy timeDetectorStrategy = new TimeDetectorStrategyImpl();
-        TimeDetectorStrategyCallbackImpl callback = new TimeDetectorStrategyCallbackImpl(context);
-        timeDetectorStrategy.initialize(callback);
+        TimeDetectorStrategyImpl.Callback callback = new TimeDetectorStrategyCallbackImpl(context);
+        TimeDetectorStrategy timeDetectorStrategy = new TimeDetectorStrategyImpl(callback);
 
         Handler handler = FgThread.getHandler();
         TimeDetectorService timeDetectorService =
@@ -133,7 +132,7 @@
     /** Internal method for handling the auto time setting being changed. */
     @VisibleForTesting
     public void handleAutoTimeDetectionChanged() {
-        mHandler.post(mTimeDetectorStrategy::handleAutoTimeDetectionChanged);
+        mHandler.post(mTimeDetectorStrategy::handleAutoTimeConfigChanged);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index e943978..f278ef6 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -16,6 +16,7 @@
 
 package com.android.server.timedetector;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.NetworkTimeSuggestion;
@@ -25,6 +26,9 @@
 
 import com.android.server.timezonedetector.Dumpable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * The interface for the class that implements the time detection algorithm used by the
  * {@link TimeDetectorService}.
@@ -37,62 +41,41 @@
  */
 public interface TimeDetectorStrategy extends Dumpable {
 
-    /**
-     * The interface used by the strategy to interact with the surrounding service.
-     *
-     * <p>Note: Because the system properties-derived value {@link #isAutoTimeDetectionEnabled()}
-     * can be modified independently and from different threads (and processes!). its use is prone
-     * to race conditions. That will be true until the responsibility for setting their values is
-     * moved to {@link TimeDetectorStrategy}. There are similar issues with
-     * {@link #systemClockMillis()} while any process can modify the system clock.
-     */
-    interface Callback {
+    @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Origin {}
 
-        /**
-         * The absolute threshold below which the system clock need not be updated. i.e. if setting
-         * the system clock would adjust it by less than this (either backwards or forwards) then it
-         * need not be set.
-         */
-        int systemClockUpdateThresholdMillis();
+    /** Used when a time value originated from a telephony signal. */
+    @Origin
+    int ORIGIN_TELEPHONY = 1;
 
-        /** Returns true if automatic time detection is enabled. */
-        boolean isAutoTimeDetectionEnabled();
+    /** Used when a time value originated from a user / manual settings. */
+    @Origin
+    int ORIGIN_MANUAL = 2;
 
-        /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
-        void acquireWakeLock();
+    /** Used when a time value originated from a network signal. */
+    @Origin
+    int ORIGIN_NETWORK = 3;
 
-        /** Returns the elapsedRealtimeMillis clock value. */
-        long elapsedRealtimeMillis();
-
-        /** Returns the system clock value. */
-        long systemClockMillis();
-
-        /** Sets the device system clock. The WakeLock must be held. */
-        void setSystemClock(long newTimeMillis);
-
-        /** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
-        void releaseWakeLock();
-    }
-
-    /** Initialize the strategy. */
-    void initialize(@NonNull Callback callback);
-
-    /** Process the suggested time from telephony sources. */
+    /** Processes the suggested time from telephony sources. */
     void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
 
     /**
-     * Process the suggested manually entered time. Returns {@code false} if the suggestion was
+     * Processes the suggested manually entered time. Returns {@code false} if the suggestion was
      * invalid, or the device configuration prevented the suggestion being used, {@code true} if the
      * suggestion was accepted. A suggestion that is valid but does not change the time because it
      * matches the current device time is considered accepted.
      */
     boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
 
-    /** Process the suggested time from network sources. */
+    /** Processes the suggested time from network sources. */
     void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
 
-    /** Handle the auto-time setting being toggled on or off. */
-    void handleAutoTimeDetectionChanged();
+    /**
+     * Handles the auto-time configuration changing For example, when the auto-time setting is
+     * toggled on or off.
+     */
+    void handleAutoTimeConfigChanged();
 
     // Utility methods below are to be moved to a better home when one becomes more obvious.
 
@@ -104,4 +87,38 @@
         return (referenceClockMillisNow - timeValue.getReferenceTimeMillis())
                 + timeValue.getValue();
     }
+
+    /**
+     * Converts one of the {@code ORIGIN_} constants to a human readable string suitable for config
+     * and debug usage. Throws an {@link IllegalArgumentException} if the value is unrecognized.
+     */
+    static String originToString(@Origin int origin) {
+        switch (origin) {
+            case ORIGIN_MANUAL:
+                return "manual";
+            case ORIGIN_NETWORK:
+                return "network";
+            case ORIGIN_TELEPHONY:
+                return "telephony";
+            default:
+                throw new IllegalArgumentException("origin=" + origin);
+        }
+    }
+
+    /**
+     * Converts a human readable config string to one of the {@code ORIGIN_} constants.
+     * Throws an {@link IllegalArgumentException} if the value is unrecognized.
+     */
+    static @Origin int stringToOrigin(String originString) {
+        switch (originString) {
+            case "manual":
+                return ORIGIN_MANUAL;
+            case "network":
+                return ORIGIN_NETWORK;
+            case "telephony":
+                return ORIGIN_TELEPHONY;
+            default:
+                throw new IllegalArgumentException("originString=" + originString);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 19484db..5b6de05 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -16,28 +16,40 @@
 
 package com.android.server.timedetector;
 
+import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
+
 import android.annotation.NonNull;
 import android.app.AlarmManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.os.Build;
+import android.os.Environment;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Slog;
 
+import java.time.Instant;
 import java.util.Objects;
 
 /**
- * The real implementation of {@link TimeDetectorStrategy.Callback} used on device.
+ * The real implementation of {@link TimeDetectorStrategyImpl.Callback} used on device.
  */
-public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrategy.Callback {
+public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrategyImpl.Callback {
 
     private final static String TAG = "timedetector.TimeDetectorStrategyCallbackImpl";
 
     private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
 
     /**
+     * Time in the past. If automatic time suggestion is before this point, it's
+     * incorrect for sure.
+     */
+    private static final Instant TIME_LOWER_BOUND = Instant.ofEpochMilli(
+            Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
+
+    /**
      * If a newly calculated system clock time and the current system clock time differs by this or
      * more the system clock will actually be updated. Used to prevent the system clock being set
      * for only minor differences.
@@ -48,6 +60,7 @@
     @NonNull private final ContentResolver mContentResolver;
     @NonNull private final PowerManager.WakeLock mWakeLock;
     @NonNull private final AlarmManager mAlarmManager;
+    @NonNull private final int[] mOriginPriorities;
 
     public TimeDetectorStrategyCallbackImpl(@NonNull Context context) {
         mContext = Objects.requireNonNull(context);
@@ -62,6 +75,15 @@
         mSystemClockUpdateThresholdMillis =
                 SystemProperties.getInt("ro.sys.time_detector_update_diff",
                         SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+
+        // TODO(b/172230856): Obtain these values from configuration.
+        String[] originStrings = { "telephony", "network" };
+        int[] origins = new int[originStrings.length];
+        for (int i = 0; i < originStrings.length; i++) {
+            int origin = stringToOrigin(originStrings[i]);
+            origins[i] = origin;
+        }
+        mOriginPriorities = origins;
     }
 
     @Override
@@ -79,6 +101,16 @@
     }
 
     @Override
+    public Instant autoTimeLowerBound() {
+        return TIME_LOWER_BOUND;
+    }
+
+    @Override
+    public int[] getAutoOriginPriorities() {
+        return mOriginPriorities;
+    }
+
+    @Override
     public void acquireWakeLock() {
         if (mWakeLock.isHeld()) {
             Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 9c18aad..d8cada5 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -16,7 +16,8 @@
 
 package com.android.server.timedetector;
 
-import android.annotation.IntDef;
+import static com.android.server.timedetector.TimeDetectorStrategy.originToString;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
@@ -33,8 +34,8 @@
 import com.android.server.timezonedetector.ArrayMapWithHistory;
 import com.android.server.timezonedetector.ReferenceWithHistory;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
+import java.util.Arrays;
 
 /**
  * An implementation of {@link TimeDetectorStrategy} that passes telephony and manual suggestions to
@@ -62,22 +63,6 @@
     static final long MAX_UTC_TIME_AGE_MILLIS =
             TELEPHONY_BUCKET_COUNT * TELEPHONY_BUCKET_SIZE_MILLIS;
 
-    @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Origin {}
-
-    /** Used when a time value originated from a telephony signal. */
-    @Origin
-    private static final int ORIGIN_TELEPHONY = 1;
-
-    /** Used when a time value originated from a user / manual settings. */
-    @Origin
-    private static final int ORIGIN_MANUAL = 2;
-
-    /** Used when a time value originated from a network signal. */
-    @Origin
-    private static final int ORIGIN_NETWORK = 3;
-
     /**
      * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
      * actual system clock time before a warning is logged. Used to help identify situations where
@@ -98,8 +83,8 @@
     @NonNull
     private final LocalLog mTimeChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
 
-    // @NonNull after initialize()
-    private Callback mCallback;
+    @NonNull
+    private final Callback mCallback;
 
     // Used to store the last time the system clock state was set automatically. It is used to
     // detect (and log) issues with the realtime clock or whether the clock is being set without
@@ -121,8 +106,59 @@
     private final ReferenceWithHistory<NetworkTimeSuggestion> mLastNetworkSuggestion =
             new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
 
-    @Override
-    public void initialize(@NonNull Callback callback) {
+    /**
+     * The interface used by the strategy to interact with the surrounding service.
+     *
+     * <p>Note: Because the system properties-derived value {@link #isAutoTimeDetectionEnabled()}
+     * can be modified independently and from different threads (and processes!), its use is prone
+     * to race conditions. That will be true until the responsibility for setting their values is
+     * moved to {@link TimeDetectorStrategy}. There are similar issues with
+     * {@link #systemClockMillis()} while any process can modify the system clock.
+     */
+    public interface Callback {
+
+        /**
+         * The absolute threshold below which the system clock need not be updated. i.e. if setting
+         * the system clock would adjust it by less than this (either backwards or forwards) then it
+         * need not be set.
+         */
+        int systemClockUpdateThresholdMillis();
+
+        /** Returns true if automatic time detection is enabled. */
+        boolean isAutoTimeDetectionEnabled();
+
+        /**
+         * Returns a lower bound for valid automatic times. It is guaranteed to be in the past,
+         * i.e. it is unrelated to the current system clock time.
+         * It holds no other meaning; it could be related to when the device system image was built,
+         * or could be updated by a mainline module.
+         */
+        @NonNull
+        Instant autoTimeLowerBound();
+
+        /**
+         * Returns the order to look at time suggestions when automatically detecting time.
+         * See {@code #ORIGIN_} constants
+         */
+        @Origin int[] getAutoOriginPriorities();
+
+        /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
+        void acquireWakeLock();
+
+        /** Returns the elapsedRealtimeMillis clock value. */
+        long elapsedRealtimeMillis();
+
+        /** Returns the system clock value. */
+        long systemClockMillis();
+
+        /** Sets the device system clock. The WakeLock must be held. */
+        void setSystemClock(long newTimeMillis);
+
+        /** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
+        void releaseWakeLock();
+    }
+
+    TimeDetectorStrategyImpl(@NonNull Callback callback) {
         mCallback = callback;
     }
 
@@ -140,7 +176,7 @@
 
     @Override
     public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion) {
-        if (!validateSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
+        if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
             return;
         }
 
@@ -174,9 +210,12 @@
             return;
         }
 
-        // Perform validation / input filtering and record the validated suggestion against the
-        // slotIndex.
-        if (!validateAndStoreTelephonySuggestion(timeSuggestion)) {
+        if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
+            return;
+        }
+
+        // Perform input filtering and record the validated suggestion against the slotIndex.
+        if (!storeTelephonySuggestion(timeSuggestion)) {
             return;
         }
 
@@ -187,12 +226,12 @@
     }
 
     @Override
-    public synchronized void handleAutoTimeDetectionChanged() {
+    public synchronized void handleAutoTimeConfigChanged() {
         boolean enabled = mCallback.isAutoTimeDetectionEnabled();
         // When automatic time detection is enabled we update the system clock instantly if we can.
         // Conversely, when automatic time detection is disabled we leave the clock as it is.
         if (enabled) {
-            String reason = "Auto time zone detection setting enabled.";
+            String reason = "Auto time zone detection config changed.";
             doAutoTimeDetection(reason);
         } else {
             // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
@@ -233,14 +272,9 @@
     }
 
     @GuardedBy("this")
-    private boolean validateAndStoreTelephonySuggestion(
+    private boolean storeTelephonySuggestion(
             @NonNull TelephonyTimeSuggestion suggestion) {
         TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
-        if (!validateSuggestionTime(newUtcTime, suggestion)) {
-            // There's probably nothing useful we can do: elsewhere we assume that reference
-            // times are in the past so just stop here.
-            return false;
-        }
 
         int slotIndex = suggestion.getSlotIndex();
         TelephonyTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex);
@@ -291,6 +325,26 @@
         return true;
     }
 
+    private boolean validateAutoSuggestionTime(
+            @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion)  {
+        return validateSuggestionTime(newUtcTime, suggestion)
+                && validateSuggestionAgainstLowerBound(newUtcTime, suggestion);
+    }
+
+    private boolean validateSuggestionAgainstLowerBound(
+            @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) {
+        Instant lowerBound = mCallback.autoTimeLowerBound();
+
+        // Suggestion is definitely wrong if it comes before lower time bound.
+        if (lowerBound.isAfter(Instant.ofEpochMilli(newUtcTime.getValue()))) {
+            Slog.w(LOG_TAG, "Suggestion points to time before lower bound, skipping it. "
+                    + "suggestion=" + suggestion + ", lower bound=" + lowerBound);
+            return false;
+        }
+
+        return true;
+    }
+
     @GuardedBy("this")
     private void doAutoTimeDetection(@NonNull String detectionReason) {
         if (!mCallback.isAutoTimeDetectionEnabled()) {
@@ -298,33 +352,44 @@
             return;
         }
 
-        // Android devices currently prioritize any telephony over network signals. There are
-        // carrier compliance tests that would need to be changed before we could ignore NITZ or
-        // prefer NTP generally. This check is cheap on devices without telephony hardware.
-        TelephonyTimeSuggestion bestTelephonySuggestion = findBestTelephonySuggestion();
-        if (bestTelephonySuggestion != null) {
-            final TimestampedValue<Long> newUtcTime = bestTelephonySuggestion.getUtcTime();
-            String cause = "Found good telephony suggestion."
-                    + ", bestTelephonySuggestion=" + bestTelephonySuggestion
-                    + ", detectionReason=" + detectionReason;
-            setSystemClockIfRequired(ORIGIN_TELEPHONY, newUtcTime, cause);
-            return;
-        }
+        // Try the different origins one at a time.
+        int[] originPriorities = mCallback.getAutoOriginPriorities();
+        for (int origin : originPriorities) {
+            TimestampedValue<Long> newUtcTime = null;
+            String cause = null;
+            if (origin == ORIGIN_TELEPHONY) {
+                TelephonyTimeSuggestion bestTelephonySuggestion = findBestTelephonySuggestion();
+                if (bestTelephonySuggestion != null) {
+                    newUtcTime = bestTelephonySuggestion.getUtcTime();
+                    cause = "Found good telephony suggestion."
+                            + ", bestTelephonySuggestion=" + bestTelephonySuggestion
+                            + ", detectionReason=" + detectionReason;
+                }
+            } else if (origin == ORIGIN_NETWORK) {
+                NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion();
+                if (networkSuggestion != null) {
+                    newUtcTime = networkSuggestion.getUtcTime();
+                    cause = "Found good network suggestion."
+                            + ", networkSuggestion=" + networkSuggestion
+                            + ", detectionReason=" + detectionReason;
+                }
+            } else {
+                Slog.w(LOG_TAG, "Unknown or unsupported origin=" + origin
+                        + " in " + Arrays.toString(originPriorities)
+                        + ": Skipping");
+            }
 
-        // There is no good telephony suggestion, try network.
-        NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion();
-        if (networkSuggestion != null) {
-            final TimestampedValue<Long> newUtcTime = networkSuggestion.getUtcTime();
-            String cause = "Found good network suggestion."
-                    + ", networkSuggestion=" + networkSuggestion
-                    + ", detectionReason=" + detectionReason;
-            setSystemClockIfRequired(ORIGIN_NETWORK, newUtcTime, cause);
-            return;
+            // Update the system clock if a good suggestion has been found.
+            if (newUtcTime != null) {
+                setSystemClockIfRequired(origin, newUtcTime, cause);
+                return;
+            }
         }
 
         if (DBG) {
-            Slog.d(LOG_TAG, "Could not determine time: No best telephony or network suggestion."
-                    + " detectionReason=" + detectionReason);
+            Slog.d(LOG_TAG, "Could not determine time: No suggestion found in"
+                    + " originPriorities=" + Arrays.toString(originPriorities)
+                    + ", detectionReason=" + detectionReason);
         }
     }
 
@@ -409,7 +474,7 @@
         // Validate first.
         TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime();
         if (!validateSuggestionUtcTime(elapsedRealtimeMillis, utcTime)) {
-            Slog.w(LOG_TAG, "Existing suggestion found to be invalid "
+            Slog.w(LOG_TAG, "Existing suggestion found to be invalid"
                     + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
                     + ", timeSuggestion=" + timeSuggestion);
             return TELEPHONY_INVALID_SCORE;
@@ -458,7 +523,7 @@
             if (!mCallback.isAutoTimeDetectionEnabled()) {
                 if (DBG) {
                     Slog.d(LOG_TAG, "Auto time detection is not enabled."
-                            + " origin=" + origin
+                            + " origin=" + originToString(origin)
                             + ", time=" + time
                             + ", cause=" + cause);
                 }
@@ -468,7 +533,7 @@
             if (mCallback.isAutoTimeDetectionEnabled()) {
                 if (DBG) {
                     Slog.d(LOG_TAG, "Auto time detection is enabled."
-                            + " origin=" + origin
+                            + " origin=" + originToString(origin)
                             + ", time=" + time
                             + ", cause=" + cause);
                 }
@@ -490,7 +555,7 @@
 
     @GuardedBy("this")
     private boolean setSystemClockUnderWakeLock(
-            int origin, @NonNull TimestampedValue<Long> newTime, @NonNull Object cause) {
+            @Origin int origin, @NonNull TimestampedValue<Long> newTime, @NonNull String cause) {
 
         long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
         boolean isOriginAutomatic = isOriginAutomatic(origin);
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
index 7652c43..fd0df8d 100644
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -129,7 +129,7 @@
     @GuardedBy("this")
     private PackageStatus getPackageStatusLocked() throws ParseException {
         try (FileInputStream fis = mPackageStatusFile.openRead()) {
-            XmlPullParser parser = parseToPackageStatusTag(fis);
+            TypedXmlPullParser parser = parseToPackageStatusTag(fis);
             Integer checkStatus = getNullableIntAttribute(parser, ATTRIBUTE_CHECK_STATUS);
             if (checkStatus == null) {
                 return null;
@@ -254,7 +254,7 @@
     @GuardedBy("this")
     private int getCurrentOptimisticLockId() throws ParseException {
         try (FileInputStream fis = mPackageStatusFile.openRead()) {
-            XmlPullParser parser = parseToPackageStatusTag(fis);
+            TypedXmlPullParser parser = parseToPackageStatusTag(fis);
             return getIntAttribute(parser, ATTRIBUTE_OPTIMISTIC_LOCK_ID);
         } catch (IOException e) {
             ParseException e2 = new ParseException("Unable to read file", 0);
@@ -264,7 +264,7 @@
     }
 
     /** Returns a parser or throws ParseException, never returns null. */
-    private static XmlPullParser parseToPackageStatusTag(FileInputStream fis)
+    private static TypedXmlPullParser parseToPackageStatusTag(FileInputStream fis)
             throws ParseException {
         try {
             TypedXmlPullParser parser = Xml.resolvePullParser(fis);
@@ -358,7 +358,7 @@
         }
     }
 
-    private static Integer getNullableIntAttribute(XmlPullParser parser, String attributeName)
+    private static Integer getNullableIntAttribute(TypedXmlPullParser parser, String attributeName)
             throws ParseException {
         String attributeValue = parser.getAttributeValue(null, attributeName);
         try {
@@ -374,7 +374,7 @@
         }
     }
 
-    private static int getIntAttribute(XmlPullParser parser, String attributeName)
+    private static int getIntAttribute(TypedXmlPullParser parser, String attributeName)
             throws ParseException {
         Integer value = getNullableIntAttribute(parser, attributeName);
         if (value == null) {
diff --git a/services/core/java/com/android/server/tv/PersistentDataStore.java b/services/core/java/com/android/server/tv/PersistentDataStore.java
index 355c385..d3c9b3b 100644
--- a/services/core/java/com/android/server/tv/PersistentDataStore.java
+++ b/services/core/java/com/android/server/tv/PersistentDataStore.java
@@ -26,6 +26,7 @@
 import android.text.TextUtils;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
@@ -166,7 +167,7 @@
             return;
         }
 
-        XmlPullParser parser;
+        TypedXmlPullParser parser;
         try {
             parser = Xml.resolvePullParser(is);
             loadFromXml(parser);
@@ -237,7 +238,7 @@
     private static final String ATTR_STRING = "string";
     private static final String ATTR_ENABLED = "enabled";
 
-    private void loadFromXml(XmlPullParser parser)
+    private void loadFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         XmlUtils.beginDocument(parser, TAG_TV_INPUT_MANAGER_STATE);
         final int outerDepth = parser.getDepth();
@@ -255,7 +256,7 @@
         }
     }
 
-    private void loadBlockedRatingsFromXml(XmlPullParser parser)
+    private void loadBlockedRatingsFromXml(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -270,7 +271,7 @@
         }
     }
 
-    private void saveToXml(XmlSerializer serializer) throws IOException {
+    private void saveToXml(TypedXmlSerializer serializer) throws IOException {
         serializer.startDocument(null, true);
         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
         serializer.startTag(null, TAG_TV_INPUT_MANAGER_STATE);
@@ -284,7 +285,7 @@
         }
         serializer.endTag(null, TAG_BLOCKED_RATINGS);
         serializer.startTag(null, TAG_PARENTAL_CONTROLS);
-        serializer.attribute(null, ATTR_ENABLED, Boolean.toString(mParentalControlsEnabled));
+        serializer.attributeBoolean(null, ATTR_ENABLED, mParentalControlsEnabled);
         serializer.endTag(null, TAG_PARENTAL_CONTROLS);
         serializer.endTag(null, TAG_TV_INPUT_MANAGER_STATE);
         serializer.endDocument();
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
index 367b966..beb11ed 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
@@ -20,6 +20,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -114,9 +115,7 @@
     protected void parseInternal(InputStream in)
             throws IOException, XmlPullParserException {
         try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
-            parser.setInput(in, null);
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
             parser.nextTag();
             readUseCase(parser);
             in.close();
@@ -137,7 +136,7 @@
         }
     }
 
-    private void readUseCase(XmlPullParser parser)
+    private void readUseCase(TypedXmlPullParser parser)
             throws XmlPullParserException, IOException {
         parser.require(XmlPullParser.START_TAG, NS, "config");
         while (parser.next() != XmlPullParser.END_TAG) {
@@ -176,7 +175,7 @@
         }
     }
 
-    private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+    private void skip(TypedXmlPullParser parser) throws XmlPullParserException, IOException {
         if (parser.getEventType() != XmlPullParser.START_TAG) {
             throw new IllegalStateException();
         }
@@ -193,7 +192,7 @@
         }
     }
 
-    private int readAttributeToInt(String attributeName, XmlPullParser parser) {
+    private int readAttributeToInt(String attributeName, TypedXmlPullParser parser) {
         return Integer.valueOf(parser.getAttributeValue(null, attributeName));
     }
 
@@ -203,7 +202,7 @@
     }
 
     @PriorityHintUseCaseType
-    private static int formatTypeToNum(String attributeName, XmlPullParser parser) {
+    private static int formatTypeToNum(String attributeName, TypedXmlPullParser parser) {
         String useCaseName = parser.getAttributeValue(null, attributeName);
         switch (useCaseName) {
             case "USE_CASE_BACKGROUND":
diff --git a/services/core/java/com/android/server/uri/TEST_MAPPING b/services/core/java/com/android/server/uri/TEST_MAPPING
index e5cda03..a9525f4a 100644
--- a/services/core/java/com/android/server/uri/TEST_MAPPING
+++ b/services/core/java/com/android/server/uri/TEST_MAPPING
@@ -7,6 +7,26 @@
                     "include-filter": "com.android.server.uri."
                 }
             ]
+        },
+        {
+            "name": "CtsAppSecurityHostTestCases",
+            "options": [
+                {
+                    "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testGrantUriPermission"
+                },
+                {
+                    "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testGrantUriPermission29"
+                },
+                {
+                    "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone"
+                },
+                {
+                    "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone28"
+                },
+                {
+                    "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone29"
+                }
+            ]
         }
     ],
     "postsubmit": [
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index bbb5374..dcc1599 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -668,22 +668,22 @@
                     if (TAG_URI_GRANT.equals(tag)) {
                         final int sourceUserId;
                         final int targetUserId;
-                        final int userHandle = readIntAttribute(in,
-                                ATTR_USER_HANDLE, UserHandle.USER_NULL);
+                        final int userHandle = in.getAttributeInt(null, ATTR_USER_HANDLE,
+                                UserHandle.USER_NULL);
                         if (userHandle != UserHandle.USER_NULL) {
                             // For backwards compatibility.
                             sourceUserId = userHandle;
                             targetUserId = userHandle;
                         } else {
-                            sourceUserId = readIntAttribute(in, ATTR_SOURCE_USER_ID);
-                            targetUserId = readIntAttribute(in, ATTR_TARGET_USER_ID);
+                            sourceUserId = in.getAttributeInt(null, ATTR_SOURCE_USER_ID);
+                            targetUserId = in.getAttributeInt(null, ATTR_TARGET_USER_ID);
                         }
                         final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
                         final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
                         final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
-                        final boolean prefix = readBooleanAttribute(in, ATTR_PREFIX);
-                        final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
-                        final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
+                        final boolean prefix = in.getAttributeBoolean(null, ATTR_PREFIX, false);
+                        final int modeFlags = in.getAttributeInt(null, ATTR_MODE_FLAGS);
+                        final long createdTime = in.getAttributeLong(null, ATTR_CREATED_TIME, now);
 
                         // Validity check that provider still belongs to source package
                         // Both direct boot aware and unaware packages are fine as we
@@ -1319,14 +1319,14 @@
             out.startTag(null, TAG_URI_GRANTS);
             for (UriPermission.Snapshot perm : persist) {
                 out.startTag(null, TAG_URI_GRANT);
-                writeIntAttribute(out, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
-                writeIntAttribute(out, ATTR_TARGET_USER_ID, perm.targetUserId);
+                out.attributeInt(null, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
+                out.attributeInt(null, ATTR_TARGET_USER_ID, perm.targetUserId);
                 out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
                 out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
                 out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
                 writeBooleanAttribute(out, ATTR_PREFIX, perm.uri.prefix);
-                writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
-                writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
+                out.attributeInt(null, ATTR_MODE_FLAGS, perm.persistedModeFlags);
+                out.attributeLong(null, ATTR_CREATED_TIME, perm.persistedCreateTime);
                 out.endTag(null, TAG_URI_GRANT);
             }
             out.endTag(null, TAG_URI_GRANTS);
diff --git a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java b/services/core/java/com/android/server/utils/DeviceConfigInterface.java
similarity index 90%
rename from services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java
rename to services/core/java/com/android/server/utils/DeviceConfigInterface.java
index ab7e7f6..ff60903 100644
--- a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java
+++ b/services/core/java/com/android/server/utils/DeviceConfigInterface.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.utils;
+package com.android.server.utils;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -54,6 +54,11 @@
     boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue);
 
     /**
+     * @see DeviceConfig#getFloat
+     */
+    float getFloat(@NonNull String namespace, @NonNull String name, float defaultValue);
+
+    /**
      * @see DeviceConfig#addOnPropertiesChangedListener
      */
     void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor,
@@ -96,6 +101,12 @@
         }
 
         @Override
+        public float getFloat(@NonNull String namespace, @NonNull String name,
+                float defaultValue) {
+            return DeviceConfig.getFloat(namespace, name, defaultValue);
+        }
+
+        @Override
         public void addOnPropertiesChangedListener(String namespace, Executor executor,
                 DeviceConfig.OnPropertiesChangedListener listener) {
             DeviceConfig.addOnPropertiesChangedListener(namespace, executor, listener);
diff --git a/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java b/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
index 12c6a7a..fe51d74 100644
--- a/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
+++ b/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
@@ -99,6 +99,7 @@
     private long mLastLogRealtimeMs;
 
     public LocalEventLog(int size) {
+        Preconditions.checkArgument(size > 0);
         mLog = new Log[size];
         mLogSize = 0;
         mLogEndIndex = 0;
@@ -163,7 +164,7 @@
 
         if (mLogSize == mLog.length) {
             // if log is full, size will remain the same, but update the start time
-            mStartRealtimeMs += event.getTimeDeltaMs();
+            mStartRealtimeMs += mLog[startIndex()].getTimeDeltaMs();
         } else {
             // otherwise add an item
             mLogSize++;
diff --git a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
new file mode 100644
index 0000000..edbc058
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.SparseArray;
+import android.view.InputDevice;
+
+import com.android.internal.annotations.GuardedBy;
+
+/** Delegates vibrations to all connected {@link InputDevice} with available {@link Vibrator}. */
+// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
+public final class InputDeviceDelegate implements InputManager.InputDeviceListener {
+    private static final String TAG = "InputDeviceDelegate";
+
+    private final Object mLock = new Object();
+    private final Handler mHandler;
+    private final InputManager mInputManager;
+
+    @GuardedBy("mLock")
+    private final SparseArray<Vibrator> mInputDeviceVibrators = new SparseArray<>();
+
+    /**
+     * Flag updated via {@link #updateInputDeviceVibrators(boolean)}, holding the value of {@link
+     * android.provider.Settings.System#VIBRATE_INPUT_DEVICES}.
+     */
+    @GuardedBy("mLock")
+    private boolean mShouldVibrateInputDevices;
+
+    public InputDeviceDelegate(Context context, Handler handler) {
+        mHandler = handler;
+        mInputManager = context.getSystemService(InputManager.class);
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        updateInputDevice(deviceId);
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        updateInputDevice(deviceId);
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        synchronized (mLock) {
+            mInputDeviceVibrators.remove(deviceId);
+        }
+    }
+
+    /**
+     * Return {@code true} is there are input devices with vibrators available and vibrations should
+     * be delegated to them.
+     */
+    public boolean isAvailable() {
+        synchronized (mLock) {
+            // mInputDeviceVibrators is cleared when settings are disabled, so this check is enough.
+            return mInputDeviceVibrators.size() > 0;
+        }
+    }
+
+    /**
+     * Vibrate all {@link InputDevice} with {@link Vibrator} available using given effect.
+     *
+     * @return {@link #isAvailable()}
+     */
+    public boolean vibrateIfAvailable(int uid, String opPkg, VibrationEffect effect,
+            String reason, VibrationAttributes attrs) {
+        synchronized (mLock) {
+            for (int i = 0; i < mInputDeviceVibrators.size(); i++) {
+                mInputDeviceVibrators.valueAt(i).vibrate(uid, opPkg, effect, reason, attrs);
+            }
+            return mInputDeviceVibrators.size() > 0;
+        }
+    }
+
+    /**
+     * Cancel vibration on all {@link InputDevice} with {@link Vibrator} available.
+     *
+     * @return {@link #isAvailable()}
+     */
+    public boolean cancelVibrateIfAvailable() {
+        synchronized (mLock) {
+            for (int i = 0; i < mInputDeviceVibrators.size(); i++) {
+                mInputDeviceVibrators.valueAt(i).cancel();
+            }
+            return mInputDeviceVibrators.size() > 0;
+        }
+    }
+
+    /**
+     * Updates the list of {@link InputDevice} vibrators based on the {@link
+     * VibrationSettings#shouldVibrateInputDevices()} setting current value and the
+     * devices currently available in {@link InputManager#getInputDeviceIds()}.
+     *
+     * @return true if there was any change in input devices available or related settings.
+     */
+    public boolean updateInputDeviceVibrators(boolean vibrateInputDevices) {
+        synchronized (mLock) {
+            if (vibrateInputDevices == mShouldVibrateInputDevices) {
+                // No need to update if settings haven't changed.
+                return false;
+            }
+
+            mShouldVibrateInputDevices = vibrateInputDevices;
+            mInputDeviceVibrators.clear();
+
+            if (vibrateInputDevices) {
+                // Register the listener first so any device added/updated/removed after the call to
+                // getInputDeviceIds() will trigger the callbacks (which will wait on the lock for
+                // this loop to finish).
+                mInputManager.registerInputDeviceListener(this, mHandler);
+
+                for (int deviceId : mInputManager.getInputDeviceIds()) {
+                    InputDevice device = mInputManager.getInputDevice(deviceId);
+                    if (device == null) {
+                        continue;
+                    }
+                    Vibrator vibrator = device.getVibrator();
+                    if (vibrator.hasVibrator()) {
+                        mInputDeviceVibrators.put(device.getId(), vibrator);
+                    }
+                }
+            } else {
+                mInputManager.unregisterInputDeviceListener(this);
+            }
+        }
+
+        return true;
+    }
+
+    private void updateInputDevice(int deviceId) {
+        synchronized (mLock) {
+            if (!mShouldVibrateInputDevices) {
+                // No need to keep this device vibrator if setting is off.
+                return;
+            }
+            InputDevice device = mInputManager.getInputDevice(deviceId);
+            if (device == null) {
+                mInputDeviceVibrators.remove(deviceId);
+                return;
+            }
+            Vibrator vibrator = device.getVibrator();
+            if (vibrator.hasVibrator()) {
+                mInputDeviceVibrators.put(deviceId, vibrator);
+            } else {
+                mInputDeviceVibrators.remove(deviceId);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
new file mode 100644
index 0000000..e2cdd02
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.ComposedProto;
+import com.android.server.OneShotProto;
+import com.android.server.PrebakedProto;
+import com.android.server.VibrationAttributesProto;
+import com.android.server.VibrationEffectProto;
+import com.android.server.VibrationProto;
+import com.android.server.WaveformProto;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/** Represents a vibration request to the vibrator service. */
+// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
+public class Vibration {
+    private static final String TAG = "Vibration";
+    private static final SimpleDateFormat DEBUG_DATE_FORMAT =
+            new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+
+    public enum Status {
+        RUNNING,
+        FINISHED,
+        FORWARDED_TO_INPUT_DEVICES,
+        CANCELLED,
+        ERROR_APP_OPS,
+        IGNORED,
+        IGNORED_APP_OPS,
+        IGNORED_BACKGROUND,
+        IGNORED_RINGTONE,
+        IGNORED_UNKNOWN_VIBRATION,
+        IGNORED_UNSUPPORTED,
+        IGNORED_FOR_ALARM,
+        IGNORED_FOR_EXTERNAL,
+        IGNORED_FOR_ONGOING,
+        IGNORED_FOR_POWER,
+        IGNORED_FOR_SETTINGS,
+    }
+
+    /** Start time in CLOCK_BOOTTIME base. */
+    public final long startTime;
+    public final VibrationAttributes attrs;
+    public final long id;
+    public final int uid;
+    public final String opPkg;
+    public final String reason;
+    public final IBinder token;
+
+    /** The actual effect to be played. */
+    @Nullable
+    private VibrationEffect mEffect;
+
+    /**
+     * The original effect that was requested. Typically these two things differ because the effect
+     * was scaled based on the users vibration intensity settings.
+     */
+    @Nullable
+    private VibrationEffect mOriginalEffect;
+
+    /**
+     * Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate
+     * with other system events, any duration calculations should be done use {@link #startTime} so
+     * as not to be affected by discontinuities created by RTC adjustments.
+     */
+    private final long mStartTimeDebug;
+    private long mEndTimeDebug;
+    private Status mStatus;
+
+    public Vibration(IBinder token, int id, VibrationEffect effect,
+            VibrationAttributes attrs, int uid, String opPkg, String reason) {
+        this.token = token;
+        this.mEffect = effect;
+        this.id = id;
+        this.startTime = SystemClock.elapsedRealtime();
+        this.attrs = attrs;
+        this.uid = uid;
+        this.opPkg = opPkg;
+        this.reason = reason;
+        mStartTimeDebug = System.currentTimeMillis();
+        mStatus = Status.RUNNING;
+    }
+
+    /**
+     * Set the {@link Status} of this vibration and the current system time as this
+     * vibration end time, for debugging purposes.
+     *
+     * <p>This method will only accept given value if the current status is {@link
+     * Status#RUNNING}.
+     */
+    public void end(Status status) {
+        if (hasEnded()) {
+            // Vibration already ended, keep first ending status set and ignore this one.
+            return;
+        }
+        mStatus = status;
+        mEndTimeDebug = System.currentTimeMillis();
+    }
+
+    /**
+     * Replace this vibration effect if given {@code scaledEffect} is different, preserving the
+     * original one for debug purposes.
+     */
+    public void updateEffect(@NonNull VibrationEffect newEffect) {
+        if (newEffect.equals(mEffect)) {
+            return;
+        }
+        mOriginalEffect = mEffect;
+        mEffect = newEffect;
+    }
+
+    /** Return true is current status is different from {@link Status#RUNNING}. */
+    public boolean hasEnded() {
+        return mStatus != Status.RUNNING;
+    }
+
+    /** Return the effect that should be played by this vibration. */
+    @Nullable
+    public VibrationEffect getEffect() {
+        return mEffect;
+    }
+
+    /** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
+    public Vibration.DebugInfo getDebugInfo() {
+        return new Vibration.DebugInfo(
+                mStartTimeDebug, mEndTimeDebug, mEffect, mOriginalEffect, /* scale= */ 0, attrs,
+                uid, opPkg, reason, mStatus);
+    }
+
+    /** Debug information about vibrations. */
+    public static final class DebugInfo {
+        private final long mStartTimeDebug;
+        private final long mEndTimeDebug;
+        private final VibrationEffect mEffect;
+        private final VibrationEffect mOriginalEffect;
+        private final float mScale;
+        private final VibrationAttributes mAttrs;
+        private final int mUid;
+        private final String mOpPkg;
+        private final String mReason;
+        private final Status mStatus;
+
+        public DebugInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect,
+                VibrationEffect originalEffect, float scale, VibrationAttributes attrs,
+                int uid, String opPkg, String reason, Status status) {
+            mStartTimeDebug = startTimeDebug;
+            mEndTimeDebug = endTimeDebug;
+            mEffect = effect;
+            mOriginalEffect = originalEffect;
+            mScale = scale;
+            mAttrs = attrs;
+            mUid = uid;
+            mOpPkg = opPkg;
+            mReason = reason;
+            mStatus = status;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                    .append("startTime: ")
+                    .append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug)))
+                    .append(", endTime: ")
+                    .append(mEndTimeDebug == 0 ? null
+                            : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
+                    .append(", status: ")
+                    .append(mStatus.name().toLowerCase())
+                    .append(", effect: ")
+                    .append(mEffect)
+                    .append(", originalEffect: ")
+                    .append(mOriginalEffect)
+                    .append(", scale: ")
+                    .append(String.format("%.2f", mScale))
+                    .append(", attrs: ")
+                    .append(mAttrs)
+                    .append(", uid: ")
+                    .append(mUid)
+                    .append(", opPkg: ")
+                    .append(mOpPkg)
+                    .append(", reason: ")
+                    .append(mReason)
+                    .toString();
+        }
+
+        /** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */
+        public void dumpProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            proto.write(VibrationProto.START_TIME, mStartTimeDebug);
+            proto.write(VibrationProto.END_TIME, mEndTimeDebug);
+            proto.write(VibrationProto.STATUS, mStatus.ordinal());
+
+            final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
+            proto.write(VibrationAttributesProto.USAGE, mAttrs.getUsage());
+            proto.write(VibrationAttributesProto.AUDIO_USAGE, mAttrs.getAudioUsage());
+            proto.write(VibrationAttributesProto.FLAGS, mAttrs.getFlags());
+            proto.end(attrsToken);
+
+            if (mEffect != null) {
+                dumpEffect(proto, VibrationProto.EFFECT, mEffect);
+            }
+            if (mOriginalEffect != null) {
+                dumpEffect(proto, VibrationProto.ORIGINAL_EFFECT, mOriginalEffect);
+            }
+
+            proto.end(token);
+        }
+
+        private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) {
+            final long token = proto.start(fieldId);
+            if (effect instanceof VibrationEffect.OneShot) {
+                dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect);
+            } else if (effect instanceof VibrationEffect.Waveform) {
+                dumpEffect(proto, VibrationEffectProto.WAVEFORM, (VibrationEffect.Waveform) effect);
+            } else if (effect instanceof VibrationEffect.Prebaked) {
+                dumpEffect(proto, VibrationEffectProto.PREBAKED, (VibrationEffect.Prebaked) effect);
+            } else if (effect instanceof VibrationEffect.Composed) {
+                dumpEffect(proto, VibrationEffectProto.COMPOSED, (VibrationEffect.Composed) effect);
+            }
+            proto.end(token);
+        }
+
+        private void dumpEffect(ProtoOutputStream proto, long fieldId,
+                VibrationEffect.OneShot effect) {
+            final long token = proto.start(fieldId);
+            proto.write(OneShotProto.DURATION, (int) effect.getDuration());
+            proto.write(OneShotProto.AMPLITUDE, effect.getAmplitude());
+            proto.end(token);
+        }
+
+        private void dumpEffect(ProtoOutputStream proto, long fieldId,
+                VibrationEffect.Waveform effect) {
+            final long token = proto.start(fieldId);
+            for (long timing : effect.getTimings()) {
+                proto.write(WaveformProto.TIMINGS, (int) timing);
+            }
+            for (int amplitude : effect.getAmplitudes()) {
+                proto.write(WaveformProto.AMPLITUDES, amplitude);
+            }
+            proto.write(WaveformProto.REPEAT, effect.getRepeatIndex() >= 0);
+            proto.end(token);
+        }
+
+        private void dumpEffect(ProtoOutputStream proto, long fieldId,
+                VibrationEffect.Prebaked effect) {
+            final long token = proto.start(fieldId);
+            proto.write(PrebakedProto.EFFECT_ID, effect.getId());
+            proto.write(PrebakedProto.EFFECT_STRENGTH, effect.getEffectStrength());
+            proto.write(PrebakedProto.FALLBACK, effect.shouldFallback());
+            proto.end(token);
+        }
+
+        private void dumpEffect(ProtoOutputStream proto, long fieldId,
+                VibrationEffect.Composed effect) {
+            final long token = proto.start(fieldId);
+            for (VibrationEffect.Composition.PrimitiveEffect primitive :
+                    effect.getPrimitiveEffects()) {
+                proto.write(ComposedProto.EFFECT_IDS, primitive.id);
+                proto.write(ComposedProto.EFFECT_SCALES, primitive.scale);
+                proto.write(ComposedProto.DELAYS, primitive.delay);
+            }
+            proto.end(token);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java
index 42a0a706..5f7e47d 100644
--- a/services/core/java/com/android/server/vibrator/VibrationScaler.java
+++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java
@@ -31,7 +31,6 @@
 
     // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
     // and the default intensity for that type of vibration (i.e. current - default).
-    private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
     private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
     private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
     private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 06a1f59..6a5d1c4 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -17,14 +17,17 @@
 package com.android.server.vibrator;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -37,6 +40,8 @@
 public final class VibrationSettings {
     private static final String TAG = "VibrationSettings";
 
+    private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = {0, 30, 100, 30};
+
     /** Listener for changes on vibration settings. */
     public interface OnVibratorSettingsChanged {
         /** Callback triggered when any of the vibrator settings change. */
@@ -51,6 +56,7 @@
 
     @GuardedBy("mLock")
     private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
+    private final SparseArray<VibrationEffect> mFallbackEffects;
 
     @GuardedBy("mLock")
     private boolean mVibrateInputDevices;
@@ -84,6 +90,23 @@
         registerSettingsObserver(
                 Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
 
+        VibrationEffect clickEffect = createEffectFromResource(
+                com.android.internal.R.array.config_virtualKeyVibePattern);
+        VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
+                DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
+        VibrationEffect heavyClickEffect = createEffectFromResource(
+                com.android.internal.R.array.config_longPressVibePattern);
+        VibrationEffect tickEffect = createEffectFromResource(
+                com.android.internal.R.array.config_clockTickVibePattern);
+
+        mFallbackEffects = new SparseArray<>();
+        mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
+        mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
+        mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
+        mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
+        mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
+                VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
+
         // Update with current values from settings.
         updateSettings();
     }
@@ -150,6 +173,17 @@
     }
 
     /**
+     * Return a {@link VibrationEffect} that should be played if the device do not support given
+     * {@code effectId}.
+     *
+     * @param effectId one of VibrationEffect.EFFECT_*
+     * @return The effect to be played as a fallback
+     */
+    public VibrationEffect getFallbackEffect(int effectId) {
+        return mFallbackEffects.get(effectId);
+    }
+
+    /**
      * Return {@code true} if the device should vibrate for ringtones.
      *
      * <p>This checks the current {@link AudioManager#getRingerModeInternal()} against user settings
@@ -270,6 +304,33 @@
                 UserHandle.USER_ALL);
     }
 
+    private VibrationEffect createEffectFromResource(int resId) {
+        long[] timings = getLongIntArray(mContext.getResources(), resId);
+        return createEffectFromTimings(timings);
+    }
+
+    private static VibrationEffect createEffectFromTimings(long[] timings) {
+        if (timings == null || timings.length == 0) {
+            return null;
+        } else if (timings.length == 1) {
+            return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
+        } else {
+            return VibrationEffect.createWaveform(timings, -1);
+        }
+    }
+
+    private static long[] getLongIntArray(Resources r, int resid) {
+        int[] ar = r.getIntArray(resid);
+        if (ar == null) {
+            return null;
+        }
+        long[] out = new long[ar.length];
+        for (int i = 0; i < ar.length; i++) {
+            out[i] = ar[i];
+        }
+        return out;
+    }
+
     /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
     private final class SettingsObserver extends ContentObserver {
         SettingsObserver(Handler handler) {
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
new file mode 100644
index 0000000..f76c1a1
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.annotation.Nullable;
+import android.hardware.vibrator.IVibrator;
+import android.os.Binder;
+import android.os.IVibratorStateListener;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Controls a single vibrator. */
+// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
+public final class VibratorController {
+    private static final String TAG = "VibratorController";
+
+    private final Object mLock = new Object();
+    private final NativeWrapper mNativeWrapper;
+    private final int mVibratorId;
+    private final long mCapabilities;
+    @Nullable
+    private final Set<Integer> mSupportedEffects;
+    @Nullable
+    private final Set<Integer> mSupportedPrimitives;
+
+    @GuardedBy("mLock")
+    private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
+            new RemoteCallbackList<>();
+    @GuardedBy("mLock")
+    private boolean mIsVibrating;
+    @GuardedBy("mLock")
+    private boolean mIsUnderExternalControl;
+
+    /** Listener for vibration completion callbacks from native. */
+    public interface OnVibrationCompleteListener {
+
+        /** Callback triggered when vibration is complete. */
+        void onComplete(int vibratorId, long vibrationId);
+    }
+
+    /**
+     * Initializes the native part of this controller, creating a global reference to given
+     * {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This
+     * wrapper is responsible for deleting this pointer by calling the method pointed
+     * by {@link #vibratorGetFinalizer()}.
+     *
+     * <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener}
+     * do not hold any strong reference to the instance responsible for deleting the returned
+     * pointer, to avoid creating a cyclic GC root reference.
+     */
+    static native long vibratorInit(int vibratorId, OnVibrationCompleteListener listener);
+
+    /**
+     * Returns pointer to native function responsible for cleaning up the native pointer allocated
+     * and returned by {@link #vibratorInit(int, OnVibrationCompleteListener)}.
+     */
+    static native long vibratorGetFinalizer();
+
+    static native boolean vibratorIsAvailable(long nativePtr);
+
+    static native void vibratorOn(long nativePtr, long milliseconds, long vibrationId);
+
+    static native void vibratorOff(long nativePtr);
+
+    static native void vibratorSetAmplitude(long nativePtr, int amplitude);
+
+    static native int[] vibratorGetSupportedEffects(long nativePtr);
+
+    static native int[] vibratorGetSupportedPrimitives(long nativePtr);
+
+    static native long vibratorPerformEffect(
+            long nativePtr, long effect, long strength, long vibrationId);
+
+    static native void vibratorPerformComposedEffect(long nativePtr,
+            VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
+
+    static native void vibratorSetExternalControl(long nativePtr, boolean enabled);
+
+    static native long vibratorGetCapabilities(long nativePtr);
+
+    static native void vibratorAlwaysOnEnable(long nativePtr, long id, long effect, long strength);
+
+    static native void vibratorAlwaysOnDisable(long nativePtr, long id);
+
+    public VibratorController(int vibratorId, OnVibrationCompleteListener listener) {
+        this(vibratorId, listener, new NativeWrapper());
+    }
+
+    @VisibleForTesting
+    public VibratorController(int vibratorId, OnVibrationCompleteListener listener,
+            NativeWrapper nativeWrapper) {
+        mVibratorId = vibratorId;
+        mNativeWrapper = nativeWrapper;
+
+        nativeWrapper.init(vibratorId, listener);
+        mCapabilities = nativeWrapper.getCapabilities();
+        mSupportedEffects = asSet(nativeWrapper.getSupportedEffects());
+        mSupportedPrimitives = asSet(nativeWrapper.getSupportedPrimitives());
+    }
+
+    /** Register state listener for this vibrator. */
+    public boolean registerVibratorStateListener(IVibratorStateListener listener) {
+        synchronized (mLock) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!mVibratorStateListeners.register(listener)) {
+                    return false;
+                }
+                // Notify its callback after new client registered.
+                notifyStateListenerLocked(listener);
+                return true;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+
+    /** Remove registered state listener for this vibrator. */
+    public boolean unregisterVibratorStateListener(IVibratorStateListener listener) {
+        synchronized (mLock) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return mVibratorStateListeners.unregister(listener);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+
+    /** Return the id of the vibrator controlled by this instance. */
+    public int getVibratorId() {
+        return mVibratorId;
+    }
+
+    /**
+     * Return {@code true} is this vibrator is currently vibrating, false otherwise.
+     *
+     * <p>This state is controlled by calls to {@link #on} and {@link #off} methods, and is
+     * automatically notified to any registered {@link IVibratorStateListener} on change.
+     */
+    public boolean isVibrating() {
+        synchronized (mLock) {
+            return mIsVibrating;
+        }
+    }
+
+    /** Return {@code true} if this vibrator is under external control, false otherwise. */
+    public boolean isUnderExternalControl() {
+        synchronized (mLock) {
+            return mIsUnderExternalControl;
+        }
+    }
+
+    /**
+     * Check against this vibrator capabilities.
+     *
+     * @param capability one of IVibrator.CAP_*
+     * @return true if this vibrator has this capability, false otherwise
+     */
+    public boolean hasCapability(long capability) {
+        return (mCapabilities & capability) == capability;
+    }
+
+    /**
+     * Check against this vibrator supported effects.
+     *
+     * @param effectIds list of effects, one of VibrationEffect.EFFECT_*
+     * @return one entry per requested effectId, with one of Vibrator.VIBRATION_EFFECT_SUPPORT_*
+     */
+    public int[] areEffectsSupported(int[] effectIds) {
+        int[] supported = new int[effectIds.length];
+        if (mSupportedEffects == null) {
+            Arrays.fill(supported, Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN);
+        } else {
+            for (int i = 0; i < effectIds.length; i++) {
+                supported[i] = mSupportedEffects.contains(effectIds[i])
+                        ? Vibrator.VIBRATION_EFFECT_SUPPORT_YES
+                        : Vibrator.VIBRATION_EFFECT_SUPPORT_NO;
+            }
+        }
+        return supported;
+    }
+
+    /**
+     * Check against this vibrator supported primitives.
+     *
+     * @param primitiveIds list of primitives, one of VibrationEffect.Composition.EFFECT_*
+     * @return one entry per requested primitiveId, with true if it is supported
+     */
+    public boolean[] arePrimitivesSupported(int[] primitiveIds) {
+        boolean[] supported = new boolean[primitiveIds.length];
+        if (mSupportedPrimitives != null && hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+            for (int i = 0; i < primitiveIds.length; i++) {
+                supported[i] = mSupportedPrimitives.contains(primitiveIds[i]);
+            }
+        }
+        return supported;
+    }
+
+    /** Return {@code true} if the underlying vibrator is currently available, false otherwise. */
+    public boolean isAvailable() {
+        return mNativeWrapper.isAvailable();
+    }
+
+    /**
+     * Set the vibrator control to be external or not, based on given flag.
+     *
+     * <p>This will affect the state of {@link #isUnderExternalControl()}.
+     */
+    public void setExternalControl(boolean externalControl) {
+        if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+            return;
+        }
+        synchronized (mLock) {
+            mIsUnderExternalControl = externalControl;
+            mNativeWrapper.setExternalControl(externalControl);
+        }
+    }
+
+    /**
+     * Update the predefined vibration effect saved with given id. This will remove the saved effect
+     * if given {@code effect} is {@code null}.
+     */
+    public void updateAlwaysOn(int id, @Nullable VibrationEffect.Prebaked effect) {
+        if (!hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+            return;
+        }
+        synchronized (mLock) {
+            if (effect == null) {
+                mNativeWrapper.alwaysOnDisable(id);
+            } else {
+                mNativeWrapper.alwaysOnEnable(id, effect.getId(), effect.getEffectStrength());
+            }
+        }
+    }
+
+    /** Set the vibration amplitude. This will NOT affect the state of {@link #isVibrating()}. */
+    public void setAmplitude(int amplitude) {
+        synchronized (mLock) {
+            if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+                mNativeWrapper.setAmplitude(amplitude);
+            }
+        }
+    }
+
+    /**
+     * Turn on the vibrator for {@code milliseconds} time, using {@code vibrationId} or completion
+     * callback to {@link OnVibrationCompleteListener}.
+     *
+     * <p>This will affect the state of {@link #isVibrating()}.
+     */
+    public void on(long milliseconds, long vibrationId) {
+        synchronized (mLock) {
+            mNativeWrapper.on(milliseconds, vibrationId);
+            notifyVibratorOnLocked();
+        }
+    }
+
+    /**
+     * Plays predefined vibration effect, using {@code vibrationId} or completion callback to
+     * {@link OnVibrationCompleteListener}.
+     *
+     * <p>This will affect the state of {@link #isVibrating()}.
+     */
+    public long on(VibrationEffect.Prebaked effect, long vibrationId) {
+        synchronized (mLock) {
+            long duration = mNativeWrapper.perform(effect.getId(), effect.getEffectStrength(),
+                    vibrationId);
+            if (duration > 0) {
+                notifyVibratorOnLocked();
+            }
+            return duration;
+        }
+    }
+
+    /**
+     * Plays composited vibration effect, using {@code vibrationId} or completion callback to
+     * {@link OnVibrationCompleteListener}.
+     *
+     * <p>This will affect the state of {@link #isVibrating()}.
+     */
+    public void on(VibrationEffect.Composed effect, long vibrationId) {
+        if (!hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+            return;
+        }
+        synchronized (mLock) {
+            mNativeWrapper.compose(effect.getPrimitiveEffects().toArray(
+                    new VibrationEffect.Composition.PrimitiveEffect[0]), vibrationId);
+            notifyVibratorOnLocked();
+        }
+    }
+
+    /** Turns off the vibrator.This will affect the state of {@link #isVibrating()}. */
+    public void off() {
+        synchronized (mLock) {
+            mNativeWrapper.off();
+            notifyVibratorOffLocked();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "VibratorController{"
+                + "mVibratorId=" + mVibratorId
+                + ", mCapabilities=" + mCapabilities
+                + ", mSupportedEffects=" + mSupportedEffects
+                + ", mSupportedPrimitives=" + mSupportedPrimitives
+                + ", mIsVibrating=" + mIsVibrating
+                + ", mIsUnderExternalControl=" + mIsUnderExternalControl
+                + ", mVibratorStateListeners count="
+                + mVibratorStateListeners.getRegisteredCallbackCount()
+                + '}';
+    }
+
+    @GuardedBy("mLock")
+    private void notifyVibratorOnLocked() {
+        if (!mIsVibrating) {
+            mIsVibrating = true;
+            notifyStateListenersLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void notifyVibratorOffLocked() {
+        if (mIsVibrating) {
+            mIsVibrating = false;
+            notifyStateListenersLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void notifyStateListenersLocked() {
+        final int length = mVibratorStateListeners.beginBroadcast();
+        try {
+            for (int i = 0; i < length; i++) {
+                notifyStateListenerLocked(mVibratorStateListeners.getBroadcastItem(i));
+            }
+        } finally {
+            mVibratorStateListeners.finishBroadcast();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void notifyStateListenerLocked(IVibratorStateListener listener) {
+        try {
+            listener.onVibrating(mIsVibrating);
+        } catch (RemoteException | RuntimeException e) {
+            Slog.e(TAG, "Vibrator state listener failed to call", e);
+        }
+    }
+
+    @Nullable
+    private static Set<Integer> asSet(int[] values) {
+        if (values == null) {
+            return null;
+        }
+        HashSet<Integer> set = new HashSet<>();
+        for (int value : values) {
+            set.add(value);
+        }
+        return set;
+    }
+
+    /** Wrapper around the static-native methods of {@link VibratorController} for tests. */
+    @VisibleForTesting
+    public static class NativeWrapper {
+
+        private long mNativePtr = 0;
+
+        /** Initializes native controller and allocation registry to destroy native instances. */
+        public void init(int vibratorId, OnVibrationCompleteListener listener) {
+            mNativePtr = VibratorController.vibratorInit(vibratorId, listener);
+            long finalizerPtr = VibratorController.vibratorGetFinalizer();
+
+            if (finalizerPtr != 0) {
+                NativeAllocationRegistry registry =
+                        NativeAllocationRegistry.createMalloced(
+                                VibratorController.class.getClassLoader(), finalizerPtr);
+                registry.registerNativeAllocation(this, mNativePtr);
+            }
+        }
+
+        /** Check if the vibrator is currently available. */
+        public boolean isAvailable() {
+            return VibratorController.vibratorIsAvailable(mNativePtr);
+        }
+
+        /** Turns vibrator on for given time. */
+        public void on(long milliseconds, long vibrationId) {
+            VibratorController.vibratorOn(mNativePtr, milliseconds, vibrationId);
+        }
+
+        /** Turns vibrator off. */
+        public void off() {
+            VibratorController.vibratorOff(mNativePtr);
+        }
+
+        /** Sets the amplitude for the vibrator to run. */
+        public void setAmplitude(int amplitude) {
+            VibratorController.vibratorSetAmplitude(mNativePtr, amplitude);
+        }
+
+        /** Returns all predefined effects supported by the device vibrator. */
+        public int[] getSupportedEffects() {
+            return VibratorController.vibratorGetSupportedEffects(mNativePtr);
+        }
+
+        /** Returns all compose primitives supported by the device vibrator. */
+        public int[] getSupportedPrimitives() {
+            return VibratorController.vibratorGetSupportedPrimitives(mNativePtr);
+        }
+
+        /** Turns vibrator on to perform one of the supported effects. */
+        public long perform(long effect, long strength, long vibrationId) {
+            return VibratorController.vibratorPerformEffect(
+                    mNativePtr, effect, strength, vibrationId);
+        }
+
+        /** Turns vibrator on to perform one of the supported composed effects. */
+        public void compose(
+                VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
+            VibratorController.vibratorPerformComposedEffect(mNativePtr, effect,
+                    vibrationId);
+        }
+
+        /** Enabled the device vibrator to be controlled by another service. */
+        public void setExternalControl(boolean enabled) {
+            VibratorController.vibratorSetExternalControl(mNativePtr, enabled);
+        }
+
+        /** Returns all capabilities of the device vibrator. */
+        public long getCapabilities() {
+            return VibratorController.vibratorGetCapabilities(mNativePtr);
+        }
+
+        /** Enable always-on vibration with given id and effect. */
+        public void alwaysOnEnable(long id, long effect, long strength) {
+            VibratorController.vibratorAlwaysOnEnable(mNativePtr, id, effect, strength);
+        }
+
+        /** Disable always-on vibration for given id. */
+        public void alwaysOnDisable(long id) {
+            VibratorController.vibratorAlwaysOnDisable(mNativePtr, id);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index e07540a..58344120 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -39,7 +39,7 @@
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
 import android.app.WallpaperManager.SetWallpaperFlags;
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.backup.WallpaperBackupHelper;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -100,12 +100,12 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.utils.TimingsTraceAndSlog;
 import com.android.server.wm.WindowManagerInternal;
@@ -114,7 +114,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -125,7 +124,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -2848,10 +2846,8 @@
         if (!uidMatchPackage) {
             return false;   // callingPackage was faked.
         }
-
-        // TODO(b/144048540): DPM needs to take into account the userId, not just the package.
-        final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
+        if (LocalServices.getService(DevicePolicyManagerInternal.class)
+                .isDeviceOrProfileOwnerInCallingUser(callingPackage)) {
             return true;
         }
         final int callingUserId = UserHandle.getCallingUserId();
@@ -2909,11 +2905,9 @@
     private void saveSettingsLocked(int userId) {
         JournaledFile journal = makeJournaledFile(userId);
         FileOutputStream fstream = null;
-        BufferedOutputStream stream = null;
         try {
             fstream = new FileOutputStream(journal.chooseForWrite(), false);
-            stream = new BufferedOutputStream(fstream);
-            TypedXmlSerializer out = Xml.resolveSerializer(stream);
+            TypedXmlSerializer out = Xml.resolveSerializer(fstream);
             out.startDocument(null, true);
 
             WallpaperData wallpaper;
@@ -2929,56 +2923,56 @@
 
             out.endDocument();
 
-            stream.flush(); // also flushes fstream
+            fstream.flush();
             FileUtils.sync(fstream);
-            stream.close(); // also closes fstream
+            fstream.close();
             journal.commit();
         } catch (IOException e) {
-            IoUtils.closeQuietly(stream);
+            IoUtils.closeQuietly(fstream);
             journal.rollback();
         }
     }
 
-    private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
+    private void writeWallpaperAttributes(TypedXmlSerializer out, String tag,
+            WallpaperData wallpaper)
             throws IllegalArgumentException, IllegalStateException, IOException {
         if (DEBUG) {
             Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
         }
         final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
         out.startTag(null, tag);
-        out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
-        out.attribute(null, "width", Integer.toString(wpdData.mWidth));
-        out.attribute(null, "height", Integer.toString(wpdData.mHeight));
+        out.attributeInt(null, "id", wallpaper.wallpaperId);
+        out.attributeInt(null, "width", wpdData.mWidth);
+        out.attributeInt(null, "height", wpdData.mHeight);
 
-        out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
-        out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
-        out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
-        out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+        out.attributeInt(null, "cropLeft", wallpaper.cropHint.left);
+        out.attributeInt(null, "cropTop", wallpaper.cropHint.top);
+        out.attributeInt(null, "cropRight", wallpaper.cropHint.right);
+        out.attributeInt(null, "cropBottom", wallpaper.cropHint.bottom);
 
         if (wpdData.mPadding.left != 0) {
-            out.attribute(null, "paddingLeft", Integer.toString(wpdData.mPadding.left));
+            out.attributeInt(null, "paddingLeft", wpdData.mPadding.left);
         }
         if (wpdData.mPadding.top != 0) {
-            out.attribute(null, "paddingTop", Integer.toString(wpdData.mPadding.top));
+            out.attributeInt(null, "paddingTop", wpdData.mPadding.top);
         }
         if (wpdData.mPadding.right != 0) {
-            out.attribute(null, "paddingRight", Integer.toString(wpdData.mPadding.right));
+            out.attributeInt(null, "paddingRight", wpdData.mPadding.right);
         }
         if (wpdData.mPadding.bottom != 0) {
-            out.attribute(null, "paddingBottom", Integer.toString(wpdData.mPadding.bottom));
+            out.attributeInt(null, "paddingBottom", wpdData.mPadding.bottom);
         }
 
         if (wallpaper.primaryColors != null) {
             int colorsCount = wallpaper.primaryColors.getMainColors().size();
-            out.attribute(null, "colorsCount", Integer.toString(colorsCount));
+            out.attributeInt(null, "colorsCount", colorsCount);
             if (colorsCount > 0) {
                 for (int i = 0; i < colorsCount; i++) {
                     final Color wc = wallpaper.primaryColors.getMainColors().get(i);
-                    out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
+                    out.attributeInt(null, "colorValue" + i, wc.toArgb());
                 }
             }
-            out.attribute(null, "colorHints",
-                    Integer.toString(wallpaper.primaryColors.getColorHints()));
+            out.attributeInt(null, "colorHints", wallpaper.primaryColors.getColorHints());
         }
 
         out.attribute(null, "name", wallpaper.name);
@@ -3028,12 +3022,8 @@
         }
     }
 
-    private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
-        String value = parser.getAttributeValue(null, name);
-        if (value == null) {
-            return defValue;
-        }
-        return Integer.parseInt(value);
+    private int getAttributeInt(TypedXmlPullParser parser, String name, int defValue) {
+        return parser.getAttributeInt(null, name, defValue);
     }
 
     /**
@@ -3213,11 +3203,11 @@
         }
     }
 
-    private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
-            boolean keepDimensionHints) {
-        final String idString = parser.getAttributeValue(null, "id");
-        if (idString != null) {
-            final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
+    private void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper,
+            boolean keepDimensionHints) throws XmlPullParserException {
+        final int id = parser.getAttributeInt(null, "id", -1);
+        if (id != -1) {
+            wallpaper.wallpaperId = id;
             if (id > mWallpaperId) {
                 mWallpaperId = id;
             }
@@ -3228,8 +3218,8 @@
         final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
 
         if (!keepDimensionHints) {
-            wpData.mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
-            wpData.mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
+            wpData.mWidth = parser.getAttributeInt(null, "width");
+            wpData.mHeight = parser.getAttributeInt(null, "height");
         }
         wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
         wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c2016de..75273ec 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
 import static android.app.ActivityOptions.ANIM_CUSTOM;
 import static android.app.ActivityOptions.ANIM_NONE;
@@ -96,18 +95,18 @@
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
+import static android.view.WindowManager.TRANSIT_OLD_UNSET;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_UNSET;
-import static android.view.WindowManager.TransitionOldType;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -183,6 +182,7 @@
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.Task.ActivityState.DESTROYED;
 import static com.android.server.wm.Task.ActivityState.DESTROYING;
 import static com.android.server.wm.Task.ActivityState.FINISHING;
@@ -194,7 +194,6 @@
 import static com.android.server.wm.Task.ActivityState.STARTED;
 import static com.android.server.wm.Task.ActivityState.STOPPED;
 import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.TaskPersister.DEBUG;
 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -277,6 +276,8 @@
 import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 import android.view.AppTransitionAnimationSpec;
 import android.view.DisplayCutout;
@@ -291,6 +292,7 @@
 import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager.TransitionOldType;
 import android.view.animation.Animation;
 import android.window.WindowContainerToken;
 
@@ -320,9 +322,7 @@
 
 import com.google.android.collect.Sets;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.IOException;
@@ -6372,14 +6372,7 @@
     }
 
     void setRequestedOrientation(int requestedOrientation) {
-        setOrientation(requestedOrientation, mayFreezeScreenLocked());
-        mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
-                task.mTaskId, requestedOrientation);
-    }
-
-    private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) {
-        final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
-        setOrientation(requestedOrientation, binder, this);
+        setOrientation(requestedOrientation, this);
 
         // Push the new configuration to the requested app in case where it's not pushed, e.g. when
         // the request is handled at task level with letterbox.
@@ -6387,6 +6380,9 @@
                 mLastReportedConfiguration.getMergedConfiguration())) {
             ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
         }
+
+        mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
+                task.mTaskId, requestedOrientation);
     }
 
     /*
@@ -6403,8 +6399,7 @@
             return;
         }
 
-        final IBinder freezeToken = mayFreezeScreenLocked() ? appToken : null;
-        if (onDescendantOrientationChanged(freezeToken, this)) {
+        if (onDescendantOrientationChanged(this)) {
             // The app is just becoming visible, and the parent Task has updated with the
             // orientation request. Update the size compat mode.
             updateSizeCompatMode();
@@ -7081,6 +7076,12 @@
             return true;
         }
 
+        if (isState(DESTROYED)) {
+            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+                    + "in destroyed state %s", this);
+            return true;
+        }
+
         if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
                     + "invisible: %s", this);
@@ -7464,9 +7465,9 @@
                 || (info.flags & FLAG_NO_HISTORY) != 0;
     }
 
-    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
-        out.attribute(null, ATTR_ID, String.valueOf(createTime));
-        out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
+    void saveToXml(TypedXmlSerializer out) throws IOException, XmlPullParserException {
+        out.attributeLong(null, ATTR_ID, createTime);
+        out.attributeInt(null, ATTR_LAUNCHEDFROMUID, launchedFromUid);
         if (launchedFromPackage != null) {
             out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
         }
@@ -7476,8 +7477,8 @@
         if (resolvedType != null) {
             out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
         }
-        out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
-        out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
+        out.attributeBoolean(null, ATTR_COMPONENTSPECIFIED, componentSpecified);
+        out.attributeInt(null, ATTR_USERID, mUserId);
 
         if (taskDescription != null) {
             taskDescription.saveToXml(out);
@@ -7494,43 +7495,20 @@
         }
     }
 
-    static ActivityRecord restoreFromXml(XmlPullParser in,
+    static ActivityRecord restoreFromXml(TypedXmlPullParser in,
             ActivityTaskSupervisor taskSupervisor) throws IOException, XmlPullParserException {
         Intent intent = null;
         PersistableBundle persistentState = null;
-        int launchedFromUid = 0;
-        String launchedFromPackage = null;
-        String launchedFromFeature = null;
-        String resolvedType = null;
-        boolean componentSpecified = false;
-        int userId = 0;
-        long createTime = -1;
+        int launchedFromUid = in.getAttributeInt(null, ATTR_LAUNCHEDFROMUID, 0);
+        String launchedFromPackage = in.getAttributeValue(null, ATTR_LAUNCHEDFROMPACKAGE);
+        String launchedFromFeature = in.getAttributeValue(null, ATTR_LAUNCHEDFROMFEATURE);
+        String resolvedType = in.getAttributeValue(null, ATTR_RESOLVEDTYPE);
+        boolean componentSpecified = in.getAttributeBoolean(null, ATTR_COMPONENTSPECIFIED, false);
+        int userId = in.getAttributeInt(null, ATTR_USERID, 0);
+        long createTime = in.getAttributeLong(null, ATTR_ID, -1);
         final int outerDepth = in.getDepth();
-        TaskDescription taskDescription = new TaskDescription();
 
-        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
-            final String attrName = in.getAttributeName(attrNdx);
-            final String attrValue = in.getAttributeValue(attrNdx);
-            if (DEBUG) Slog.d(TaskPersister.TAG,
-                        "ActivityRecord: attribute name=" + attrName + " value=" + attrValue);
-            if (ATTR_ID.equals(attrName)) {
-                createTime = Long.parseLong(attrValue);
-            } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) {
-                launchedFromUid = Integer.parseInt(attrValue);
-            } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
-                launchedFromPackage = attrValue;
-            } else if (ATTR_LAUNCHEDFROMFEATURE.equals(attrName)) {
-                launchedFromFeature = attrValue;
-            } else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
-                resolvedType = attrValue;
-            } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
-                componentSpecified = Boolean.parseBoolean(attrValue);
-            } else if (ATTR_USERID.equals(attrName)) {
-                userId = Integer.parseInt(attrValue);
-            } else if (!attrName.startsWith(ATTR_TASKDESCRIPTION_PREFIX)) {
-                Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
-            }
-        }
+        TaskDescription taskDescription = new TaskDescription();
         taskDescription.restoreFromXml(in);
 
         int event;
@@ -7584,6 +7562,10 @@
         return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
     }
 
+    String getProcessName() {
+        return info.applicationInfo.processName;
+    }
+
     int getUid() {
         return info.applicationInfo.uid;
     }
@@ -7596,6 +7578,14 @@
         return app != null ? app.getPid() : 0;
     }
 
+    int getLaunchedFromPid() {
+        return launchedFromPid;
+    }
+
+    int getLaunchedFromUid() {
+        return launchedFromUid;
+    }
+
     /**
      * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
      * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index acee7b2..b88b54e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -57,9 +57,6 @@
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
-import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
@@ -71,6 +68,9 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
+import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
+import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
+import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
 import static com.android.server.wm.Task.ActivityState.RESUMED;
@@ -1870,7 +1870,7 @@
         }
 
         mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,
-                sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);
+                sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams, mRequest);
         mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea()
                 ? mLaunchParams.mPreferredTaskDisplayArea
                 : mRootWindowContainer.getDefaultTaskDisplayArea();
@@ -2031,12 +2031,12 @@
      */
     private int deliverToCurrentTopIfNeeded(Task topStack, NeededUriGrants intentGrants) {
         final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
-        final boolean dontStart = top != null && mStartActivity.resultTo == null
+        final boolean dontStart = top != null
                 && top.mActivityComponent.equals(mStartActivity.mActivityComponent)
                 && top.mUserId == mStartActivity.mUserId
                 && top.attachedToProcess()
                 && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
-                || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK))
+                || LAUNCH_SINGLE_TOP == mLaunchMode)
                 // This allows home activity to automatically launch on secondary task display area
                 // when it was added, if home was the top activity on default task display area,
                 // instead of sending new intent to the home activity on default display area.
@@ -2057,6 +2057,13 @@
             return START_RETURN_INTENT_TO_CALLER;
         }
 
+        if (mStartActivity.resultTo != null) {
+            mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho,
+                    mStartActivity.requestCode, RESULT_CANCELED,
+                    null /* data */, null /* dataGrants */);
+            mStartActivity.resultTo = null;
+        }
+
         deliverNewIntent(top, intentGrants);
 
         // Don't use mStartActivity.task to show the toast. We're not starting a new activity but
@@ -2254,7 +2261,7 @@
         // Preferred display id is the only state we need for now and it could be updated again
         // after we located a reusable task (which might be resided in another display).
         mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
-                sourceRecord, options, PHASE_DISPLAY, mLaunchParams);
+                sourceRecord, options, PHASE_DISPLAY, mLaunchParams, mRequest);
         mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea()
                 ? mLaunchParams.mPreferredTaskDisplayArea
                 : mRootWindowContainer.getDefaultTaskDisplayArea();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 27faf13..8ba76be 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1056,7 +1056,7 @@
         }
 
         @Override
-        public void onUserUnlocking(@NonNull TargetUser user) {
+        public void onUserUnlocked(@NonNull TargetUser user) {
             synchronized (mService.getGlobalLock()) {
                 mService.mTaskSupervisor.onUserUnlocked(user.getUserIdentifier());
             }
@@ -2738,9 +2738,8 @@
         }
     }
 
-    @Override
-    public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
-        return getFilteredTasks(maxNum, false /* filterForVisibleRecents */);
+    List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
+        return getTasks(maxNum, false /* filterForVisibleRecents */);
     }
 
     /**
@@ -2748,7 +2747,7 @@
      *                                 be visible in the recent task list in systemui
      */
     @Override
-    public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
+    public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum,
             boolean filterOnlyVisibleRecents) {
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 37f04ce..d0c26af 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -186,7 +186,7 @@
     private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 13;
     private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14;
     private static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 15;
-    private static final int REPORT_HOME_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 16;
+    private static final int START_HOME_MSG = FIRST_SUPERVISOR_STACK_MSG + 16;
     private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 17;
 
     // Used to indicate that windows of activities should be preserved during the resize.
@@ -446,6 +446,9 @@
         // unlocked.
         mPersisterQueue.startPersisting();
         mLaunchParamsPersister.onUnlockUser(userId);
+
+        // Need to launch home again for those displays that do not have encryption aware home app.
+        scheduleStartHome("userUnlocked");
     }
 
     public ActivityMetricsLogger getActivityMetricsLogger() {
@@ -956,13 +959,17 @@
 
     void updateHomeProcess(WindowProcessController app) {
         if (app != null && mService.mHomeProcess != app) {
-            if (!mHandler.hasMessages(REPORT_HOME_CHANGED_MSG)) {
-                mHandler.sendEmptyMessage(REPORT_HOME_CHANGED_MSG);
-            }
+            scheduleStartHome("homeChanged");
             mService.mHomeProcess = app;
         }
     }
 
+    private void scheduleStartHome(String reason) {
+        if (!mHandler.hasMessages(START_HOME_MSG)) {
+            mHandler.obtainMessage(START_HOME_MSG, reason).sendToTarget();
+        }
+    }
+
     private void logIfTransactionTooLarge(Intent intent, Bundle icicle) {
         int extrasSize = 0;
         if (intent != null) {
@@ -1315,6 +1322,7 @@
         if (mRootWindowContainer.allResumedActivitiesIdle()) {
             if (r != null) {
                 mService.scheduleAppGcsLocked();
+                mRecentTasks.onActivityIdle(r);
             }
 
             if (mLaunchingActivityWakeLock.isHeld()) {
@@ -2472,11 +2480,11 @@
                         handleLaunchTaskBehindCompleteLocked(r);
                     }
                 } break;
-                case REPORT_HOME_CHANGED_MSG: {
-                    mHandler.removeMessages(REPORT_HOME_CHANGED_MSG);
+                case START_HOME_MSG: {
+                    mHandler.removeMessages(START_HOME_MSG);
 
                     // Start home activities on displays with no activities.
-                    mRootWindowContainer.startHomeOnEmptyDisplays("homeChanged");
+                    mRootWindowContainer.startHomeOnEmptyDisplays((String) msg.obj);
                 } break;
                 case TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG: {
                     final ActivityRecord r = (ActivityRecord) msg.obj;
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index d40dea2..55200b5 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -492,7 +492,7 @@
                 }
                 out.startTag(null, "package");
                 out.attribute(null, "name", pkg);
-                out.attribute(null, "flags", Integer.toString(mode));
+                out.attributeInt(null, "flags", mode);
                 out.endTag(null, "package");
             }
 
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 89c5f62..4b34954 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -43,7 +43,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -113,14 +112,7 @@
                             if ("pkg".equals(tagName)) {
                                 String pkg = parser.getAttributeValue(null, "name");
                                 if (pkg != null) {
-                                    String mode = parser.getAttributeValue(null, "mode");
-                                    int modeInt = 0;
-                                    if (mode != null) {
-                                        try {
-                                            modeInt = Integer.parseInt(mode);
-                                        } catch (NumberFormatException e) {
-                                        }
-                                    }
+                                    int modeInt = parser.getAttributeInt(null, "mode", 0);
                                     mPackages.put(pkg, modeInt);
                                 }
                             }
@@ -396,7 +388,7 @@
                 }
                 out.startTag(null, "pkg");
                 out.attribute(null, "name", pkg);
-                out.attribute(null, "mode", Integer.toString(mode));
+                out.attributeInt(null, "mode", mode);
                 out.endTag(null, "pkg");
             }
 
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 60a62dc..36a1ef9 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -182,6 +182,11 @@
         // writing to proto (which has significant cost if we write a lot of empty configurations).
         mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
         mRequestedOverrideConfiguration.setTo(overrideConfiguration);
+        final Rect newBounds = mRequestedOverrideConfiguration.windowConfiguration.getBounds();
+        if (mHasOverrideConfiguration && providesMaxBounds()
+                && diffRequestedOverrideMaxBounds(newBounds) != BOUNDS_CHANGE_NONE) {
+            mRequestedOverrideConfiguration.windowConfiguration.setMaxBounds(newBounds);
+        }
         // Update full configuration of this container and all its children.
         final ConfigurationContainer parent = getParent();
         onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
@@ -341,9 +346,6 @@
 
         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
         mRequestsTmpConfig.windowConfiguration.setBounds(bounds);
-        if (overrideMaxBounds) {
-            mRequestsTmpConfig.windowConfiguration.setMaxBounds(bounds);
-        }
         onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
 
         return boundsChange;
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 8ad2958..a4ac16f 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -33,7 +33,6 @@
 import android.annotation.Nullable;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.os.IBinder;
 import android.util.proto.ProtoOutputStream;
 import android.window.DisplayAreaInfo;
 import android.window.IDisplayAreaOrganizer;
@@ -151,12 +150,11 @@
     }
 
     @Override
-    boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
-            WindowContainer requestingContainer) {
+    boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
         // If this is set to ignore the orientation request, we don't propagate descendant
         // orientation request.
         return !mIgnoreOrientationRequest
-                && super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
+                && super.onDescendantOrientationChanged(requestingContainer);
     }
 
     /**
@@ -382,6 +380,13 @@
 
     @Nullable
     @Override
+    <R> R getItemFromDisplayAreas(Function<DisplayArea, R> callback) {
+        final R item = super.getItemFromDisplayAreas(callback);
+        return item != null ? item : callback.apply(this);
+    }
+
+    @Nullable
+    @Override
     <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
             boolean traverseTopToBottom) {
         // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children.
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 43b9a21..c475da3 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -16,7 +16,10 @@
 
 package com.android.server.wm;
 
+import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
+
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+import static com.android.server.wm.DisplayArea.Type.ANY;
 
 import android.content.pm.ParceledListSlice;
 import android.os.Binder;
@@ -26,6 +29,7 @@
 import android.window.DisplayAreaAppearedInfo;
 import android.window.IDisplayAreaOrganizer;
 import android.window.IDisplayAreaOrganizerController;
+import android.window.WindowContainerToken;
 
 import com.android.internal.protolog.common.ProtoLog;
 
@@ -36,6 +40,12 @@
 public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub {
     private static final String TAG = "DisplayAreaOrganizerController";
 
+    /**
+     * Next available feature id for a runtime task display area.
+     * @see #createTaskDisplayArea(IDisplayAreaOrganizer organizer, int, int, String)
+     */
+    private int mNextTaskDisplayAreaFeatureId = FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
+
     final ActivityTaskManagerService mService;
     private final WindowManagerGlobalLock mGlobalLock;
     private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap();
@@ -92,10 +102,8 @@
                 final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>();
                 mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
                     if (da.mFeatureId != feature) return;
-                    da.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
-                    displayAreaInfos.add(new DisplayAreaAppearedInfo(da.getDisplayAreaInfo(),
-                            new SurfaceControl(da.getSurfaceControl(),
-                                    "DisplayAreaOrganizerController.registerOrganizer")));
+                    displayAreaInfos.add(organizeDisplayArea(organizer, da,
+                            "DisplayAreaOrganizerController.registerOrganizer"));
                 });
 
                 mOrganizersByFeatureIds.put(feature, organizer);
@@ -124,6 +132,77 @@
         }
     }
 
+    @Override
+    public DisplayAreaAppearedInfo createTaskDisplayArea(IDisplayAreaOrganizer organizer,
+            int displayId, int rootFeatureId, String name) {
+        enforceTaskPermission("createTaskDisplayArea()");
+        final long uid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create TaskDisplayArea uid=%d", uid);
+
+                final DisplayContent display =
+                        mService.mRootWindowContainer.getDisplayContent(displayId);
+                if (display == null) {
+                    throw new IllegalArgumentException("createTaskDisplayArea unknown displayId="
+                            + displayId);
+                }
+
+                final DisplayArea root = display.getItemFromDisplayAreas(da ->
+                        da.asRootDisplayArea() != null && da.mFeatureId == rootFeatureId
+                                ? da
+                                : null);
+                if (root == null) {
+                    throw new IllegalArgumentException("Can't find RootDisplayArea with featureId="
+                            + rootFeatureId);
+                }
+
+                final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
+                final DeathRecipient dr = new DeathRecipient(organizer, taskDisplayAreaFeatureId);
+                try {
+                    organizer.asBinder().linkToDeath(dr, 0);
+                } catch (RemoteException e) {
+                    // Oh well...
+                }
+
+                final TaskDisplayArea tda = createTaskDisplayArea(root.asRootDisplayArea(), name,
+                        taskDisplayAreaFeatureId);
+                return organizeDisplayArea(organizer, tda,
+                        "DisplayAreaOrganizerController.createTaskDisplayArea");
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void deleteTaskDisplayArea(WindowContainerToken token) {
+        enforceTaskPermission("deleteTaskDisplayArea()");
+        final long uid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete TaskDisplayArea uid=%d", uid);
+
+                final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
+                if (wc == null || wc.asTaskDisplayArea() == null) {
+                    throw new IllegalArgumentException("Can't resolve TaskDisplayArea from token");
+                }
+                final TaskDisplayArea taskDisplayArea = wc.asTaskDisplayArea();
+                if (!taskDisplayArea.mCreatedByOrganizer) {
+                    throw new IllegalArgumentException(
+                            "Attempt to delete TaskDisplayArea not created by organizer "
+                                    + "TaskDisplayArea=" + taskDisplayArea);
+                }
+
+                deleteTaskDisplayArea(taskDisplayArea);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName());
         try {
@@ -157,8 +236,71 @@
         IBinder organizerBinder = organizer.asBinder();
         mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
             if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
-                da.setOrganizer(null);
+                if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
+                    // Delete the organizer created TDA when unregister.
+                    deleteTaskDisplayArea(da.asTaskDisplayArea());
+                } else {
+                    da.setOrganizer(null);
+                }
             }
         });
     }
+
+    private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer,
+            DisplayArea displayArea, String callsite) {
+        displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
+        return new DisplayAreaAppearedInfo(displayArea.getDisplayAreaInfo(),
+                new SurfaceControl(displayArea.getSurfaceControl(), callsite));
+    }
+
+    private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,
+            int taskDisplayAreaFeatureId) {
+        final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent,
+                root.mWmService, name, taskDisplayAreaFeatureId, true /* createdByOrganizer */);
+
+        // Find the top most DA that can contain Task (either a TDA or a DisplayAreaGroup).
+        final DisplayArea topTaskContainer = root.getItemFromDisplayAreas(da -> {
+            if (da.mType != ANY) {
+                return null;
+            }
+
+            final RootDisplayArea rootDA = da.getRootDisplayArea();
+            if (rootDA == root || rootDA == da) {
+                // Either it is the top TDA below the root or it is a DisplayAreaGroup.
+                return da;
+            }
+            return null;
+        });
+        if (topTaskContainer == null) {
+            throw new IllegalStateException("Root must either contain TDA or DAG root=" + root);
+        }
+
+        // Insert the TaskDisplayArea as the top Task container.
+        final WindowContainer parent = topTaskContainer.getParent();
+        final int index = parent.mChildren.indexOf(topTaskContainer) + 1;
+        parent.addChild(taskDisplayArea, index);
+
+        return taskDisplayArea;
+    }
+
+    private void deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
+        taskDisplayArea.setOrganizer(null);
+        mService.mRootWindowContainer.mTaskSupervisor.beginDeferResume();
+
+        // TaskDisplayArea#remove() move the stacks to the default TaskDisplayArea.
+        Task lastReparentedStack;
+        try {
+            lastReparentedStack = taskDisplayArea.remove();
+        } finally {
+            mService.mRootWindowContainer.mTaskSupervisor.endDeferResume();
+        }
+
+        taskDisplayArea.removeImmediately();
+
+        // Only update focus/visibility for the last one because there may be many stacks are
+        // reparented and the intermediate states are unnecessary.
+        if (lastReparentedStack != null) {
+            lastReparentedStack.postReparent();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 80ec722..6a42087 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -172,10 +172,16 @@
             throw new IllegalStateException("Root must be set for the display area policy.");
         }
 
+        final Set<Integer> rootIdSet = new ArraySet<>();
+        rootIdSet.add(mRootHierarchyBuilder.mRoot.mFeatureId);
         boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
         boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
         for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
             HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
+            if (!rootIdSet.add(hierarchyBuilder.mRoot.mFeatureId)) {
+                throw new IllegalStateException("There should not be two RootDisplayAreas with id "
+                        + hierarchyBuilder.mRoot.mFeatureId);
+            }
             if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
                 throw new IllegalStateException(
                         "DisplayAreaGroup must contain at least one TaskDisplayArea.");
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4133ea2..5df5050 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -55,6 +55,8 @@
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.systemBars;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -91,7 +93,6 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
-import static com.android.server.wm.DisplayContentProto.CAN_SHOW_IME;
 import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
 import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
@@ -103,6 +104,7 @@
 import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
 import static com.android.server.wm.DisplayContentProto.ID;
 import static com.android.server.wm.DisplayContentProto.IME_INSETS_SOURCE_PROVIDER;
+import static com.android.server.wm.DisplayContentProto.IME_POLICY;
 import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_CONTROL_TARGET;
 import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_INPUT_TARGET;
 import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_TARGET;
@@ -203,6 +205,7 @@
 import android.view.SurfaceSession;
 import android.view.WindowInsets;
 import android.view.WindowManager;
+import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -556,6 +559,9 @@
      */
     InsetsControlTarget mInputMethodControlTarget;
 
+    /** The surface parent of the IME container. */
+    private SurfaceControl mInputMethodSurfaceParent;
+
     /** If true hold off on modifying the animation layer of mInputMethodTarget */
     boolean mInputMethodTargetWaitingAnim;
 
@@ -1297,10 +1303,9 @@
     }
 
     @Override
-    boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
-            WindowContainer requestingContainer) {
+    boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
         final Configuration config = updateOrientation(
-                getRequestedOverrideConfiguration(), freezeDisplayToken, false /* forceUpdate */);
+                getRequestedOverrideConfiguration(), requestingContainer, false /* forceUpdate */);
         // If display rotation class tells us that it doesn't consider app requested orientation,
         // this display won't rotate just because of an app changes its requested orientation. Thus
         // it indicates that this display chooses not to handle this request.
@@ -1352,11 +1357,11 @@
      * @param currentConfig The current requested override configuration (it is usually set from
      *                      the last {@link #sendNewConfiguration}) of the display. It is used to
      *                      check if the configuration container has the latest state.
-     * @param freezeDisplayToken Freeze the app window token if the orientation is changed.
+     * @param freezeDisplayWindow Freeze the app window if the orientation is changed.
      * @param forceUpdate See {@link DisplayRotation#updateRotationUnchecked(boolean)}
      */
-    Configuration updateOrientation(Configuration currentConfig, IBinder freezeDisplayToken,
-            boolean forceUpdate) {
+    Configuration updateOrientation(Configuration currentConfig,
+            WindowContainer freezeDisplayWindow, boolean forceUpdate) {
         if (!mDisplayReady) {
             return null;
         }
@@ -1365,9 +1370,9 @@
         if (updateOrientation(forceUpdate)) {
             // If we changed the orientation but mOrientationChangeComplete is already true,
             // we used seamless rotation, and we don't need to freeze the screen.
-            if (freezeDisplayToken != null && !mWmService.mRoot.mOrientationChangeComplete) {
-                final ActivityRecord activity = getActivityRecord(freezeDisplayToken);
-                if (activity != null) {
+            if (freezeDisplayWindow != null && !mWmService.mRoot.mOrientationChangeComplete) {
+                final ActivityRecord activity = freezeDisplayWindow.asActivityRecord();
+                if (activity != null && activity.mayFreezeScreenLocked()) {
                     activity.startFreezingScreen();
                 }
             }
@@ -1674,6 +1679,28 @@
         }
     }
 
+    void notifyInsetsChanged(Consumer<WindowState> dispatchInsetsChanged) {
+        if (mFixedRotationLaunchingApp != null) {
+            // The insets state of fixed rotation app is a rotated copy. Make sure the visibilities
+            // of insets sources are consistent with the latest state.
+            final InsetsState rotatedState =
+                    mFixedRotationLaunchingApp.getFixedRotationTransformInsetsState();
+            if (rotatedState != null) {
+                final InsetsState state = mInsetsStateController.getRawInsetsState();
+                for (int i = 0; i < InsetsState.SIZE; i++) {
+                    final InsetsSource source = state.peekSource(i);
+                    if (source != null) {
+                        rotatedState.setSourceVisible(i, source.isVisible());
+                    }
+                }
+            }
+        }
+        forAllWindows(dispatchInsetsChanged, true /* traverseTopToBottom */);
+        if (mRemoteInsetsControlTarget != null) {
+            mRemoteInsetsControlTarget.notifyInsetsChanged();
+        }
+    }
+
     /**
      * Update rotation of the display.
      *
@@ -2930,7 +2957,7 @@
             mInsetsStateController.getImeSourceProvider().dumpDebug(proto,
                     IME_INSETS_SOURCE_PROVIDER, logLevel);
         }
-        proto.write(CAN_SHOW_IME, canShowIme());
+        proto.write(IME_POLICY, getImePolicy());
         proto.end(token);
     }
 
@@ -3561,7 +3588,8 @@
      * @return {@link InsetsControlTarget} that can host IME.
      */
     InsetsControlTarget getImeHostOrFallback(WindowState target) {
-        if (target != null && target.getDisplayContent().canShowIme()) {
+        if (target != null
+                && target.getDisplayContent().getImePolicy() == DISPLAY_IME_POLICY_LOCAL) {
             return target;
         }
         return getImeFallback();
@@ -3575,12 +3603,17 @@
         return statusBar != null ? statusBar : defaultDc.mRemoteInsetsControlTarget;
     }
 
-    boolean canShowIme() {
+    @DisplayImePolicy int getImePolicy() {
         if (!isTrusted()) {
-            return false;
+            return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
         }
-        return mWmService.mDisplayWindowSettings.shouldShowImeLocked(this)
-                || forceDesktopMode();
+        final int imePolicy = mWmService.mDisplayWindowSettings.getImePolicyLocked(this);
+        if (imePolicy == DISPLAY_IME_POLICY_FALLBACK_DISPLAY && forceDesktopMode()) {
+            // If the display has not explicitly requested for the IME to be hidden then it shall
+            // show the IME locally.
+            return DISPLAY_IME_POLICY_LOCAL;
+        }
+        return imePolicy;
     }
 
     boolean forceDesktopMode() {
@@ -3601,7 +3634,9 @@
         ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target);
         mInputMethodTarget = target;
         mInputMethodTargetWaitingAnim = targetWaitingAnim;
-        assignWindowLayers(true /* setLayoutNeeded */);
+
+        // 1. Reparent the IME container window to the target root DA to get the correct bounds and
+        // config. (Only happens when the target window is in a different root DA)
         if (target != null) {
             RootDisplayArea targetRoot = target.getRootDisplayArea();
             if (targetRoot != null) {
@@ -3610,7 +3645,13 @@
                 targetRoot.placeImeContainer(mImeWindowsContainers);
             }
         }
+        // 2. Reparent the IME container surface to either the input target app, or the IME window
+        // parent.
         updateImeParent();
+        // 3. Assign window layers based on the IME surface parent to make sure it is on top of the
+        // app.
+        assignWindowLayers(true /* setLayoutNeeded */);
+        // 4. Update the IME control target to apply any inset change and animation.
         updateImeControlTarget();
     }
 
@@ -3640,7 +3681,8 @@
 
     void updateImeParent() {
         final SurfaceControl newParent = computeImeParent();
-        if (newParent != null) {
+        if (newParent != null && newParent != mInputMethodSurfaceParent) {
+            mInputMethodSurfaceParent = newParent;
             getPendingTransaction().reparent(mImeWindowsContainers.mSurfaceControl, newParent);
             scheduleAnimation();
         }
@@ -4417,18 +4459,15 @@
         //
         // In the case of split-screen windowing mode, we need to elevate the IME above the
         // docked divider while keeping the app itself below the docked divider, so instead
-        // we use relative layering of the IME targets child windows, and place the IME in
-        // the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}).
+        // we will put the docked divider below the IME. @see #assignRelativeLayerForImeTargetChild
         //
         // In the case the IME target is animating, the animation Z order may be different
         // than the WindowContainer Z order, so it's difficult to be sure we have the correct
-        // IME target. In this case we just layer the IME over all transitions by placing it
-        // in the above applications layer.
+        // IME target. In this case we just layer the IME over its parent surface.
         //
-        // In the case where we have no IME target we assign it where its base layer would
-        // place it in the AboveAppWindowContainers.
+        // In the case where we have no IME target we let its window parent to place it.
         //
-        // Keep IME window in mAboveAppWindowsContainers as long as app's starting window
+        // Keep IME window in surface parent as long as app's starting window
         // exists so it get's layered above the starting window.
         if (imeTarget != null && !(imeTarget.mActivityRecord != null
                 && imeTarget.mActivityRecord.hasStartingWindow()) && (
@@ -4439,6 +4478,11 @@
                     // TODO: We need to use an extra level on the app surface to ensure
                     // this is always above SurfaceView but always below attached window.
                     1);
+        } else if (mInputMethodSurfaceParent != null) {
+            // The IME surface parent may not be its window parent's surface
+            // (@see #computeImeParent), so set relative layer here instead of letting the window
+            // parent to assign layer.
+            mImeWindowsContainers.assignRelativeLayer(t, mInputMethodSurfaceParent, 1);
         }
         super.assignChildLayers(t);
     }
@@ -5188,7 +5232,7 @@
         mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);
         super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
         mCurrentOverrideConfigurationChanges = 0;
-        mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
+        mWmService.setNewDisplayOverrideConfiguration(currOverrideConfig, this);
         mAtmService.addWindowLayoutReasons(
                 ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
     }
@@ -5680,4 +5724,8 @@
         }
         return count;
     }
+
+    MagnificationSpec getMagnificationSpec() {
+        return mMagnificationSpec;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f14a2ee..826b725 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -66,7 +66,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -279,7 +278,6 @@
     private volatile boolean mKeyguardDrawComplete;
     private volatile boolean mWindowManagerDrawComplete;
 
-    private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
     private WindowState mStatusBar = null;
     private WindowState mNotificationShade = null;
     private final int[] mStatusBarHeightForRotation = new int[4];
@@ -864,19 +862,7 @@
      * @param attrs The window layout parameters to be modified.  These values
      * are modified in-place.
      */
-    public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
-            int callingPid, int callingUid) {
-
-        final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
-        if (mScreenDecorWindows.contains(win)) {
-            if (!isScreenDecor) {
-                // No longer has the flag set, so remove from the set.
-                mScreenDecorWindows.remove(win);
-            }
-        } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
-            mScreenDecorWindows.add(win);
-        }
-
+    public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) {
         switch (attrs.type) {
             case TYPE_SYSTEM_OVERLAY:
             case TYPE_SECURE_SYSTEM_OVERLAY:
@@ -966,11 +952,6 @@
      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
      */
     int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) {
-        if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
-            mContext.enforcePermission(
-                    android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
-                    "DisplayPolicy");
-        }
         if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
             mContext.enforcePermission(
                     android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
@@ -1090,10 +1071,6 @@
      * @param attrs Information about the window to be added.
      */
     void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
-        if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
-            mScreenDecorWindows.add(win);
-        }
-
         switch (attrs.type) {
             case TYPE_NOTIFICATION_SHADE:
                 mNotificationShade = win;
@@ -1275,7 +1252,6 @@
         if (mLastFocusedWindow == win) {
             mLastFocusedWindow = null;
         }
-        mScreenDecorWindows.remove(win);
     }
 
     private int getStatusBarHeight(DisplayFrames displayFrames) {
@@ -1457,14 +1433,12 @@
         }
 
         final int fl = attrs.flags;
-        final int pfl = attrs.privateFlags;
         final boolean layoutInScreenAndInsetDecor = (fl & FLAG_LAYOUT_IN_SCREEN) != 0
                 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
-        final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
         final DisplayFrames displayFrames = isFixedRotationTransforming
                 ? windowToken.getFixedRotationTransformDisplayFrames()
                 : mDisplayContent.mDisplayFrames;
-        if (layoutInScreenAndInsetDecor && !screenDecor) {
+        if (layoutInScreenAndInsetDecor) {
             outDisplayCutout.set(
                     displayFrames.mDisplayCutout.calculateRelativeTo(outFrame).getDisplayCutout());
         } else {
@@ -1564,7 +1538,6 @@
                     simulatedWindowFrames, barContentFrames,
                     contentFrame -> layoutStatusBar(displayFrames, contentFrame));
         }
-        layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
     }
 
     /**
@@ -1585,7 +1558,6 @@
 
         layoutNavigationBar(displayFrames, uiMode, null /* simulatedContentFrame */);
         layoutStatusBar(displayFrames, null /* simulatedContentFrame */);
-        layoutScreenDecorWindows(displayFrames, null /* simulatedFrames */);
     }
 
     void updateHideNavInputEventReceiver() {
@@ -1640,47 +1612,6 @@
         state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(u.left, s.bottom, u.right, u.bottom);
     }
 
-    /**
-     * Layout the decor windows with {@link #PRIVATE_FLAG_IS_SCREEN_DECOR}.
-     *
-     * @param displayFrames The display frames to be layouted.
-     * @param simulatedFrames Non-null if the caller only needs the result of display frames (see
-     *                        {@link WindowState#mSimulatedWindowFrames}).
-     */
-    private void layoutScreenDecorWindows(DisplayFrames displayFrames,
-            WindowFrames simulatedFrames) {
-        if (mScreenDecorWindows.isEmpty()) {
-            return;
-        }
-
-        sTmpRect.setEmpty();
-        final int displayId = displayFrames.mDisplayId;
-
-        for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
-            final WindowState w = mScreenDecorWindows.valueAt(i);
-            if (w.getDisplayId() != displayId || !w.isVisible()) {
-                // Skip if not on the same display or not visible.
-                continue;
-            }
-
-            final boolean isSimulatedLayout = simulatedFrames != null;
-            if (isSimulatedLayout) {
-                w.setSimulatedWindowFrames(simulatedFrames);
-            }
-            getRotatedWindowBounds(displayFrames, w, sTmpScreenDecorFrame);
-            final WindowFrames windowFrames = w.getLayoutingWindowFrames();
-            windowFrames.setFrames(sTmpScreenDecorFrame /* parentFrame */,
-                    sTmpScreenDecorFrame /* displayFrame */);
-            try {
-                w.computeFrame(displayFrames);
-            } finally {
-                if (isSimulatedLayout) {
-                    w.setSimulatedWindowFrames(null);
-                }
-            }
-        }
-    }
-
     private void layoutStatusBar(DisplayFrames displayFrames, Rect simulatedContentFrame) {
         // decide where the status bar goes ahead of time
         if (mStatusBar == null) {
@@ -1819,8 +1750,7 @@
         // We've already done the navigation bar, status bar, and all screen decor windows. If the
         // status bar can receive input, we need to layout it again to accommodate for the IME
         // window.
-        if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
-                || mScreenDecorWindows.contains(win)) {
+        if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar) {
             return;
         }
         final WindowManager.LayoutParams attrs = win.getAttrs();
@@ -2772,7 +2702,11 @@
                 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
             return false;
         }
-
+        if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen
+                && ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0) {
+            mService.mInputManager.setSystemUiLightsOut(
+                    isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
+        }
         mLastDisableFlags = disableFlags;
         mLastAppearance = appearance;
         mLastFullscreenAppearance = fullscreenAppearance;
@@ -2802,10 +2736,6 @@
 
             }
         });
-        if (mDisplayContent.isDefaultDisplay) {
-            mService.mInputManager.setSystemUiLightsOut(
-                    isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
-        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 472678c..5d4dbc8 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -19,6 +19,8 @@
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
@@ -31,6 +33,7 @@
 import android.view.DisplayInfo;
 import android.view.IWindowManager;
 import android.view.Surface;
+import android.view.WindowManager.DisplayImePolicy;
 
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.DisplayContent.ForceScalingMode;
@@ -212,22 +215,23 @@
         mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
-    boolean shouldShowImeLocked(DisplayContent dc) {
+    @DisplayImePolicy int getImePolicyLocked(DisplayContent dc) {
         if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
             // Default display should show IME.
-            return true;
+            return DISPLAY_IME_POLICY_LOCAL;
         }
 
         final DisplayInfo displayInfo = dc.getDisplayInfo();
         final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
-        return settings.mShouldShowIme != null ? settings.mShouldShowIme : false;
+        return settings.mImePolicy != null ? settings.mImePolicy
+                : DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
     }
 
-    void setShouldShowImeLocked(DisplayContent dc, boolean shouldShow) {
+    void setDisplayImePolicy(DisplayContent dc, @DisplayImePolicy int imePolicy) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
         final SettingsProvider.SettingsEntry overrideSettings =
                 mSettingsProvider.getOverrideSettings(displayInfo);
-        overrideSettings.mShouldShowIme = shouldShow;
+        overrideSettings.mImePolicy = imePolicy;
         mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
@@ -343,7 +347,7 @@
             @Nullable
             Boolean mShouldShowSystemDecors;
             @Nullable
-            Boolean mShouldShowIme;
+            Integer mImePolicy;
             @Nullable
             Integer mFixedToUserRotation;
             @Nullable
@@ -406,8 +410,8 @@
                     mShouldShowSystemDecors = other.mShouldShowSystemDecors;
                     changed = true;
                 }
-                if (other.mShouldShowIme != mShouldShowIme) {
-                    mShouldShowIme = other.mShouldShowIme;
+                if (!Objects.equals(other.mImePolicy, mImePolicy)) {
+                    mImePolicy = other.mImePolicy;
                     changed = true;
                 }
                 if (!Objects.equals(other.mFixedToUserRotation, mFixedToUserRotation)) {
@@ -481,9 +485,9 @@
                     mShouldShowSystemDecors = delta.mShouldShowSystemDecors;
                     changed = true;
                 }
-                if (delta.mShouldShowIme != null
-                        && delta.mShouldShowIme != mShouldShowIme) {
-                    mShouldShowIme = delta.mShouldShowIme;
+                if (delta.mImePolicy != null
+                        && !Objects.equals(delta.mImePolicy, mImePolicy)) {
+                    mImePolicy = delta.mImePolicy;
                     changed = true;
                 }
                 if (delta.mFixedToUserRotation != null
@@ -509,7 +513,7 @@
                         && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
                         && mShouldShowWithInsecureKeyguard == null
                         && mShouldShowSystemDecors == null
-                        && mShouldShowIme == null
+                        && mImePolicy == null
                         && mFixedToUserRotation == null
                         && mIgnoreOrientationRequest == null;
             }
@@ -530,7 +534,7 @@
                         && Objects.equals(mShouldShowWithInsecureKeyguard,
                                 that.mShouldShowWithInsecureKeyguard)
                         && Objects.equals(mShouldShowSystemDecors, that.mShouldShowSystemDecors)
-                        && Objects.equals(mShouldShowIme, that.mShouldShowIme)
+                        && Objects.equals(mImePolicy, that.mImePolicy)
                         && Objects.equals(mFixedToUserRotation, that.mFixedToUserRotation)
                         && Objects.equals(mIgnoreOrientationRequest,
                                 that.mIgnoreOrientationRequest);
@@ -540,7 +544,7 @@
             public int hashCode() {
                 return Objects.hash(mWindowingMode, mUserRotationMode, mUserRotation, mForcedWidth,
                         mForcedHeight, mForcedDensity, mForcedScalingMode, mRemoveContentMode,
-                        mShouldShowWithInsecureKeyguard, mShouldShowSystemDecors, mShouldShowIme,
+                        mShouldShowWithInsecureKeyguard, mShouldShowSystemDecors, mImePolicy,
                         mFixedToUserRotation, mIgnoreOrientationRequest);
             }
 
@@ -557,7 +561,7 @@
                         + ", mRemoveContentMode=" + mRemoveContentMode
                         + ", mShouldShowWithInsecureKeyguard=" + mShouldShowWithInsecureKeyguard
                         + ", mShouldShowSystemDecors=" + mShouldShowSystemDecors
-                        + ", mShouldShowIme=" + mShouldShowIme
+                        + ", mShouldShowIme=" + mImePolicy
                         + ", mFixedToUserRotation=" + mFixedToUserRotation
                         + ", mIgnoreOrientationRequest=" + mIgnoreOrientationRequest
                         + '}';
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index 83da136e..aa603ab 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -16,7 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -35,13 +37,11 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 import com.android.server.wm.DisplayWindowSettings.SettingsProvider;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -49,7 +49,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -336,36 +335,31 @@
         return fileData;
     }
 
-    private static int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
-        try {
-            final String str = parser.getAttributeValue(null, name);
-            return str != null ? Integer.parseInt(str) : defaultValue;
-        } catch (NumberFormatException e) {
-            Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
-            return defaultValue;
-        }
+    private static int getIntAttribute(TypedXmlPullParser parser, String name, int defaultValue) {
+        return parser.getAttributeInt(null, name, defaultValue);
     }
 
     @Nullable
-    private static Integer getIntegerAttribute(XmlPullParser parser, String name,
+    private static Integer getIntegerAttribute(TypedXmlPullParser parser, String name,
             @Nullable Integer defaultValue) {
         try {
-            final String str = parser.getAttributeValue(null, name);
-            return str != null ? Integer.valueOf(str) : defaultValue;
-        } catch (NumberFormatException e) {
-            Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+            return parser.getAttributeInt(null, name);
+        } catch (Exception ignored) {
             return defaultValue;
         }
     }
 
     @Nullable
-    private static Boolean getBooleanAttribute(XmlPullParser parser, String name,
+    private static Boolean getBooleanAttribute(TypedXmlPullParser parser, String name,
             @Nullable Boolean defaultValue) {
-        final String str = parser.getAttributeValue(null, name);
-        return str != null ? Boolean.valueOf(str) : defaultValue;
+        try {
+            return parser.getAttributeBoolean(null, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
     }
 
-    private static void readDisplay(XmlPullParser parser, FileData fileData)
+    private static void readDisplay(TypedXmlPullParser parser, FileData fileData)
             throws NumberFormatException, XmlPullParserException, IOException {
         String name = parser.getAttributeValue(null, "name");
         if (name != null) {
@@ -390,8 +384,15 @@
                     "shouldShowWithInsecureKeyguard", null /* defaultValue */);
             settingsEntry.mShouldShowSystemDecors = getBooleanAttribute(parser,
                     "shouldShowSystemDecors", null /* defaultValue */);
-            settingsEntry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme",
+            final Boolean shouldShowIme = getBooleanAttribute(parser, "shouldShowIme",
                     null /* defaultValue */);
+            if (shouldShowIme != null) {
+                settingsEntry.mImePolicy = shouldShowIme ? DISPLAY_IME_POLICY_LOCAL
+                        : DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+            } else {
+                settingsEntry.mImePolicy = getIntegerAttribute(parser, "imePolicy",
+                        null /* defaultValue */);
+            }
             settingsEntry.mFixedToUserRotation = getIntegerAttribute(parser, "fixedToUserRotation",
                     null /* defaultValue */);
             settingsEntry.mIgnoreOrientationRequest = getBooleanAttribute(parser,
@@ -401,7 +402,7 @@
         XmlUtils.skipCurrentTag(parser);
     }
 
-    private static void readConfig(XmlPullParser parser, FileData fileData)
+    private static void readConfig(TypedXmlPullParser parser, FileData fileData)
             throws NumberFormatException,
             XmlPullParserException, IOException {
         fileData.mIdentifierType = getIntAttribute(parser, "identifier",
@@ -426,8 +427,7 @@
             out.startTag(null, "display-settings");
 
             out.startTag(null, "config");
-            out.attribute(null, "identifier",
-                    Integer.toString(data.mIdentifierType));
+            out.attributeInt(null, "identifier", data.mIdentifierType);
             out.endTag(null, "config");
 
             for (Map.Entry<String, SettingsEntry> entry
@@ -441,8 +441,7 @@
                 out.startTag(null, "display");
                 out.attribute(null, "name", displayIdentifier);
                 if (settingsEntry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
-                    out.attribute(null, "windowingMode",
-                            Integer.toString(settingsEntry.mWindowingMode));
+                    out.attributeInt(null, "windowingMode", settingsEntry.mWindowingMode);
                 }
                 if (settingsEntry.mUserRotationMode != null) {
                     out.attribute(null, "userRotationMode",
@@ -453,22 +452,18 @@
                             settingsEntry.mUserRotation.toString());
                 }
                 if (settingsEntry.mForcedWidth != 0 && settingsEntry.mForcedHeight != 0) {
-                    out.attribute(null, "forcedWidth",
-                            Integer.toString(settingsEntry.mForcedWidth));
-                    out.attribute(null, "forcedHeight",
-                            Integer.toString(settingsEntry.mForcedHeight));
+                    out.attributeInt(null, "forcedWidth", settingsEntry.mForcedWidth);
+                    out.attributeInt(null, "forcedHeight", settingsEntry.mForcedHeight);
                 }
                 if (settingsEntry.mForcedDensity != 0) {
-                    out.attribute(null, "forcedDensity",
-                            Integer.toString(settingsEntry.mForcedDensity));
+                    out.attributeInt(null, "forcedDensity", settingsEntry.mForcedDensity);
                 }
                 if (settingsEntry.mForcedScalingMode != null) {
                     out.attribute(null, "forcedScalingMode",
                             settingsEntry.mForcedScalingMode.toString());
                 }
                 if (settingsEntry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
-                    out.attribute(null, "removeContentMode",
-                            Integer.toString(settingsEntry.mRemoveContentMode));
+                    out.attributeInt(null, "removeContentMode", settingsEntry.mRemoveContentMode);
                 }
                 if (settingsEntry.mShouldShowWithInsecureKeyguard != null) {
                     out.attribute(null, "shouldShowWithInsecureKeyguard",
@@ -478,9 +473,8 @@
                     out.attribute(null, "shouldShowSystemDecors",
                             settingsEntry.mShouldShowSystemDecors.toString());
                 }
-                if (settingsEntry.mShouldShowIme != null) {
-                    out.attribute(null, "shouldShowIme",
-                            settingsEntry.mShouldShowIme.toString());
+                if (settingsEntry.mImePolicy != null) {
+                    out.attributeInt(null, "imePolicy", settingsEntry.mImePolicy);
                 }
                 if (settingsEntry.mFixedToUserRotation != null) {
                     out.attribute(null, "fixedToUserRotation",
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index cdc14cd..92baadf 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -27,7 +27,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
-import com.android.server.wm.utils.DeviceConfigInterface;
+import com.android.server.utils.DeviceConfigInterface;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/wm/ImpressionAttestationController.java b/services/core/java/com/android/server/wm/ImpressionAttestationController.java
index 4793e1b..b0afc57 100644
--- a/services/core/java/com/android/server/wm/ImpressionAttestationController.java
+++ b/services/core/java/com/android/server/wm/ImpressionAttestationController.java
@@ -18,6 +18,9 @@
 
 import static android.service.attestation.ImpressionAttestationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS;
 
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -29,7 +32,9 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.hardware.HardwareBuffer;
 import android.os.Binder;
 import android.os.Bundle;
@@ -43,6 +48,7 @@
 import android.service.attestation.ImpressionAttestationService;
 import android.service.attestation.ImpressionToken;
 import android.util.Slog;
+import android.view.MagnificationSpec;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -59,7 +65,8 @@
  * blocking calls into another service.
  */
 public class ImpressionAttestationController {
-    private static final String TAG = "ImpressionAttestationController";
+    private static final String TAG =
+            TAG_WITH_CLASS_NAME ? "ImpressionAttestationController" : TAG_WM;
     private static final boolean DEBUG = false;
 
     private final Object mServiceConnectionLock = new Object();
@@ -81,6 +88,10 @@
 
     private final String mSalt;
 
+    private final float[] mTmpFloat9 = new float[9];
+    private final Matrix mTmpMatrix = new Matrix();
+    private final RectF mTmpRectF = new RectF();
+
     private interface Command {
         void run(IImpressionAttestationService service) throws RemoteException;
     }
@@ -151,6 +162,79 @@
     }
 
     /**
+     * Calculate the bounds to take the screenshot when generating the impression token. This takes
+     * into account window transform, magnification, and display bounds.
+     *
+     * Call while holding {@link WindowManagerService#mGlobalLock}
+     *
+     * @param win Window that the impression token is generated for.
+     * @param boundsInWindow The bounds passed in about where in the window to take the screenshot.
+     * @param outBounds The result of the calculated bounds
+     */
+    void calculateImpressionTokenBoundsLocked(WindowState win, Rect boundsInWindow,
+            Rect outBounds) {
+        if (DEBUG) {
+            Slog.d(TAG, "calculateImpressionTokenBounds: boundsInWindow=" + boundsInWindow);
+        }
+        outBounds.set(boundsInWindow);
+
+        DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
+
+        // Intersect boundsInWindow with the window to make sure it's not outside the window
+        // requesting the token. Offset the window bounds to 0,0 since the boundsInWindow are
+        // offset from the window location, not display.
+        final Rect windowBounds = new Rect();
+        win.getBounds(windowBounds);
+        windowBounds.offsetTo(0, 0);
+        outBounds.intersectUnchecked(windowBounds);
+
+        if (DEBUG) {
+            Slog.d(TAG, "calculateImpressionTokenBounds: boundsIntersectWindow=" + outBounds);
+        }
+
+        if (outBounds.isEmpty()) {
+            return;
+        }
+
+        // Transform the bounds using the window transform in case there's a scale or offset.
+        // This allows the bounds to be in display space.
+        win.getTransformationMatrix(mTmpFloat9, mTmpMatrix);
+        mTmpRectF.set(outBounds);
+        mTmpMatrix.mapRect(mTmpRectF, mTmpRectF);
+        outBounds.set((int) mTmpRectF.left, (int) mTmpRectF.top, (int) mTmpRectF.right,
+                (int) mTmpRectF.bottom);
+        if (DEBUG) {
+            Slog.d(TAG, "calculateImpressionTokenBounds: boundsInDisplay=" + outBounds);
+        }
+
+        // Apply the magnification spec values to the bounds since the content could be magnified
+        final MagnificationSpec magSpec = displayContent.getMagnificationSpec();
+        if (magSpec != null) {
+            outBounds.scale(magSpec.scale);
+            outBounds.offset((int) magSpec.offsetX, (int) magSpec.offsetY);
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG, "calculateImpressionTokenBounds: boundsWithMagnification=" + outBounds);
+        }
+
+        if (outBounds.isEmpty()) {
+            return;
+        }
+
+        // Intersect with the display bounds since it shouldn't take a screenshot of content
+        // outside the display since it's not visible to the user.
+        final Rect displayBounds = displayContent.getBounds();
+        outBounds.intersectUnchecked(displayBounds);
+        if (DEBUG) {
+            Slog.d(TAG, "calculateImpressionTokenBounds: finalBounds=" + outBounds);
+        }
+    }
+
+    /**
      * Run a command, starting the service connection if necessary.
      */
     private void connectAndRun(@NonNull Command command) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index efd9e2a..25d779f 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -40,6 +40,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
@@ -523,9 +524,9 @@
             if (w.mInputChannelToken == null || w.mRemoved
                     || (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
                 if (w.mWinAnimator.hasSurface()) {
-                    // Assign an InputInfo with type to the overlay window which can't receive input
-                    // event. This is used to omit Surfaces from occlusion detection.
-                    populateOverlayInputInfo(inputWindowHandle, w.isVisible());
+                    // Make sure the input info can't receive input event. It may be omitted from
+                    // occlusion detection depending on the type or if it's a trusted overlay.
+                    populateOverlayInputInfo(inputWindowHandle, w);
                     setInputWindowInfoIfNeeded(mInputTransaction,
                             w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
                     return;
@@ -603,6 +604,12 @@
         }
     }
 
+    static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
+            WindowState w) {
+        populateOverlayInputInfo(inputWindowHandle, w.isVisible());
+        inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
+    }
+
     // This would reset InputWindowHandle fields to prevent it could be found by input event.
     // We need to check if any new field of InputWindowHandle could impact the result.
     @VisibleForTesting
@@ -649,6 +656,7 @@
                 || type == TYPE_SECURE_SYSTEM_OVERLAY
                 || type == TYPE_DOCK_DIVIDER
                 || type == TYPE_ACCESSIBILITY_OVERLAY
-                || type == TYPE_INPUT_CONSUMER;
+                || type == TYPE_INPUT_CONSUMER
+                || type == TYPE_VOICE_INTERACTION;
     }
 }
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 9d70fd7..752d6b4 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -496,10 +496,7 @@
     }
 
     void notifyInsetsChanged() {
-        mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */);
-        if (mDisplayContent.mRemoteInsetsControlTarget != null) {
-            mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged();
-        }
+        mDisplayContent.notifyInsetsChanged(mDispatchInsetsChanged);
     }
 
     void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c3b6149..ebd91a0 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -206,9 +206,8 @@
                     mAodShowing ? 1 : 0,
                     1 /* keyguardGoingAway */,
                     "keyguardGoingAway");
-            mRootWindowContainer.getDefaultDisplay()
-                    .prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
-                            convertTransitFlags(flags));
+            mRootWindowContainer.getDefaultDisplay().requestTransitionAndLegacyPrepare(
+                    TRANSIT_KEYGUARD_GOING_AWAY, convertTransitFlags(flags));
             updateKeyguardSleepToken();
 
             // Some stack visibility might change (e.g. docked stack)
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index f1ae921..b6b172e 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.server.wm.ActivityStarter.Request;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
@@ -73,9 +74,10 @@
      * @param source    The {@link ActivityRecord} from which activity was started from.
      * @param options   The {@link ActivityOptions} specified for the activity.
      * @param result    The resulting params.
+     * @param request   The optional request from the activity starter.
      */
-    void calculate(Task task, WindowLayout layout, ActivityRecord activity,
-                   ActivityRecord source, ActivityOptions options, int phase, LaunchParams result) {
+    void calculate(Task task, WindowLayout layout, ActivityRecord activity, ActivityRecord source,
+            ActivityOptions options, int phase, LaunchParams result, @Nullable Request request) {
         result.reset();
 
         if (task != null || activity != null) {
@@ -91,7 +93,7 @@
             final LaunchParamsModifier modifier = mModifiers.get(i);
 
             switch(modifier.onCalculate(task, layout, activity, source, options, phase, mTmpCurrent,
-                    mTmpResult)) {
+                    mTmpResult, request)) {
                 case RESULT_SKIP:
                     // Do not apply any results when we are told to skip
                     continue;
@@ -128,7 +130,8 @@
 
     boolean layoutTask(Task task, WindowLayout layout, ActivityRecord activity,
             ActivityRecord source, ActivityOptions options) {
-        calculate(task, layout, activity, source, options, PHASE_BOUNDS, mTmpParams);
+        calculate(task, layout, activity, source, options, PHASE_BOUNDS, mTmpParams,
+                null /* request */);
 
         // No changes, return.
         if (mTmpParams.isEmpty()) {
@@ -305,15 +308,17 @@
          *                      launched should have this be non-null.
          * @param source        the Activity that launched a new task. Could be {@code null}.
          * @param options       {@link ActivityOptions} used to start the activity with.
-         * @param phase         the calculation phase, see {@link LaunchParamsModifier.Phase}
+         * @param phase         the calculation phase, see {@link Phase}
          * @param currentParams launching params after the process of last {@link
          *                      LaunchParamsModifier}.
          * @param outParams     the result params to be set.
+         * @param request       Optional data to give more context on the launch
          * @return see {@link LaunchParamsModifier.Result}
          */
         @Result
-        int onCalculate(Task task, WindowLayout layout, ActivityRecord activity,
+        int onCalculate(@Nullable Task task, WindowLayout layout, ActivityRecord activity,
                 ActivityRecord source, ActivityOptions options, @Phase int phase,
-                LaunchParams currentParams, LaunchParams outParams);
+                LaunchParams currentParams, LaunchParams outParams,
+                @Nullable Request request);
     }
 }
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 2f8cfdd..391e659 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -27,26 +27,24 @@
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.view.DisplayInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.server.LocalServices;
 import com.android.server.pm.PackageList;
 import com.android.server.wm.LaunchParamsController.LaunchParams;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.io.StringWriter;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -195,12 +193,9 @@
                 continue;
             }
 
-            BufferedReader reader = null;
-            try {
-                reader = new BufferedReader(new FileReader(paramsFile));
+            try (InputStream in = new FileInputStream(paramsFile)) {
                 final PersistableLaunchParams params = new PersistableLaunchParams();
-                final XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(reader);
+                final TypedXmlPullParser parser = Xml.resolvePullParser(in);
                 int event;
                 while ((event = parser.next()) != XmlPullParser.END_DOCUMENT
                         && event != XmlPullParser.END_TAG) {
@@ -223,8 +218,6 @@
             } catch (Exception e) {
                 Slog.w(TAG, "Failed to restore launch params for " + name, e);
                 filesToDelete.add(paramsFile);
-            } finally {
-                IoUtils.closeQuietly(reader);
             }
         }
 
@@ -410,12 +403,11 @@
             mLaunchParams = launchParams;
         }
 
-        private StringWriter saveParamsToXml() {
-            final StringWriter writer = new StringWriter();
-            final XmlSerializer serializer = new FastXmlSerializer();
-
+        private byte[] saveParamsToXml() {
             try {
-                serializer.setOutput(writer);
+                final ByteArrayOutputStream os = new ByteArrayOutputStream();
+                final TypedXmlSerializer serializer = Xml.resolveSerializer(os);
+
                 serializer.startDocument(/* encoding */ null, /* standalone */ true);
                 serializer.startTag(null, TAG_LAUNCH_PARAMS);
 
@@ -425,7 +417,7 @@
                 serializer.endDocument();
                 serializer.flush();
 
-                return writer;
+                return os.toByteArray();
             } catch (IOException e) {
                 return null;
             }
@@ -433,7 +425,7 @@
 
         @Override
         public void process() {
-            final StringWriter writer = saveParamsToXml();
+            final byte[] data = saveParamsToXml();
 
             final File launchParamFolder = getLaunchParamFolder(mUserId);
             if (!launchParamFolder.isDirectory() && !launchParamFolder.mkdirs()) {
@@ -447,7 +439,7 @@
             FileOutputStream stream = null;
             try {
                 stream = atomicFile.startWrite();
-                stream.write(writer.toString().getBytes());
+                stream.write(data);
             } catch (Exception e) {
                 Slog.e(TAG, "Failed to write param file for " + mComponentName, e);
                 if (stream != null) {
@@ -513,17 +505,16 @@
          */
         long mTimestamp;
 
-        void saveToXml(XmlSerializer serializer) throws IOException {
+        void saveToXml(TypedXmlSerializer serializer) throws IOException {
             serializer.attribute(null, ATTR_DISPLAY_UNIQUE_ID, mDisplayUniqueId);
-            serializer.attribute(null, ATTR_WINDOWING_MODE,
-                    Integer.toString(mWindowingMode));
+            serializer.attributeInt(null, ATTR_WINDOWING_MODE, mWindowingMode);
             serializer.attribute(null, ATTR_BOUNDS, mBounds.flattenToString());
             if (mWindowLayoutAffinity != null) {
                 serializer.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
             }
         }
 
-        void restore(File xmlFile, XmlPullParser parser) {
+        void restore(File xmlFile, TypedXmlPullParser parser) {
             for (int i = 0; i < parser.getAttributeCount(); ++i) {
                 final String attrValue = parser.getAttributeValue(i);
                 switch (parser.getAttributeName(i)) {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index a750e2c..ba6b27a 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -181,6 +181,9 @@
     /** The non-empty tasks that are removed from recent tasks (see {@link #removeForAddTask}). */
     private final ArrayList<Task> mHiddenTasks = new ArrayList<>();
 
+    /** Whether to trim inactive tasks when activities are idle. */
+    private boolean mCheckTrimmableTasksOnIdle;
+
     // These values are generally loaded from resources, but can be set dynamically in the tests
     private boolean mHasVisibleRecentTasks;
     private int mGlobalMaxNumTasks;
@@ -1045,16 +1048,6 @@
     void add(Task task) {
         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
 
-        // Only allow trimming task if it is not updating visibility for activities, so the caller
-        // doesn't need to handle unexpected size and index when looping task containers.
-        final boolean canTrimTask = !mSupervisor.inActivityVisibilityUpdate();
-
-        // Clean up the hidden tasks when going to home because the user may not be unable to return
-        // to the task from recents.
-        if (canTrimTask && !mHiddenTasks.isEmpty() && task.isActivityTypeHome()) {
-            removeUnreachableHiddenTasks(task.getWindowingMode());
-        }
-
         final boolean isAffiliated = task.mAffiliatedTaskId != task.mTaskId
                 || task.mNextAffiliateTaskId != INVALID_TASK_ID
                 || task.mPrevAffiliateTaskId != INVALID_TASK_ID;
@@ -1183,10 +1176,7 @@
             cleanupLocked(task.mUserId);
         }
 
-        // Trim the set of tasks to the active set
-        if (canTrimTask) {
-            trimInactiveRecentTasks();
-        }
+        mCheckTrimmableTasksOnIdle = true;
         notifyTaskPersisterLocked(task, false /* flush */);
     }
 
@@ -1213,6 +1203,22 @@
     }
 
     /**
+     * Called when an activity reports idle. The caller should not be in any loop that iterates
+     * window hierarchy. so it is safe (e.g. index out of bound) to remove inactive tasks.
+     */
+    void onActivityIdle(ActivityRecord r) {
+        // Clean up the hidden tasks when going to home because the user may not be unable to return
+        // to the task from recents.
+        if (!mHiddenTasks.isEmpty() && r.isActivityTypeHome()) {
+            removeUnreachableHiddenTasks(r.getWindowingMode());
+        }
+        if (mCheckTrimmableTasksOnIdle) {
+            mCheckTrimmableTasksOnIdle = false;
+            trimInactiveRecentTasks();
+        }
+    }
+
+    /**
      * Trims the recents task list to the global max number of recents.
      */
     private void trimInactiveRecentTasks() {
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index 1e5d045..da04f43 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -57,6 +57,11 @@
         return this;
     }
 
+    @Override
+    RootDisplayArea asRootDisplayArea() {
+        return this;
+    }
+
     /** Whether the orientation (based on dimensions) of this root is different from the Display. */
     boolean isOrientationDifferentFromDisplay() {
         return false;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 7073548..cbeaecf 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1804,10 +1804,7 @@
         Configuration config = null;
         if (displayContent != null) {
             config = displayContent.updateOrientation(
-                    getDisplayOverrideConfiguration(displayId),
-                    starting != null && starting.mayFreezeScreenLocked()
-                            ? starting.appToken : null,
-                    true /* forceUpdate */);
+                    getDisplayOverrideConfiguration(displayId), starting, true /* forceUpdate */);
         }
         // Visibilities may change so let the starting activity have a chance to report. Can't do it
         // when visibility is changed in each AppWindowToken because it may trigger wrong
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b46e796..c414c64 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -38,7 +38,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.Nullable;
-import android.app.ActivityManagerInternal;
 import android.app.PendingIntent;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -56,6 +55,7 @@
 import android.os.RemoteException;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.service.attestation.ImpressionToken;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.MergedConfiguration;
@@ -848,4 +848,15 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
+
+    @Override
+    public ImpressionToken generateImpressionToken(IWindow window, Rect boundsInWindow,
+            String hashAlgorithm) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            return mService.generateImpressionToken(this, window, boundsInWindow, hashAlgorithm);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ebf5989..fb441fa 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -196,6 +196,8 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
 import android.view.RemoteAnimationAdapter;
@@ -2249,7 +2251,7 @@
             // the rotation animation needs to capture snapshot earlier to avoid animating from
             // an intermediate state.
             if (oldOrientation != getOrientation()) {
-                onDescendantOrientationChanged(null, this);
+                onDescendantOrientationChanged(this);
             }
         } finally {
             if (pipChanging) {
@@ -3305,9 +3307,8 @@
     }
 
     @Override
-    public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
-            WindowContainer requestingContainer) {
-        if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
+    public boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
+        if (super.onDescendantOrientationChanged(requestingContainer)) {
             return true;
         }
 
@@ -4099,6 +4100,7 @@
                 ? rootTask.mTaskId
                 : INVALID_TASK_ID;
         info.isFocused = isFocused();
+        info.isVisible = hasVisibleChildren();
     }
 
     @Nullable PictureInPictureParams getPictureInPictureParams() {
@@ -4483,14 +4485,14 @@
     /**
      * Saves this {@link Task} to XML using given serializer.
      */
-    void saveToXml(XmlSerializer out) throws Exception {
+    void saveToXml(TypedXmlSerializer out) throws Exception {
         if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
 
-        out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
+        out.attributeInt(null, ATTR_TASKID, mTaskId);
         if (realActivity != null) {
             out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
         }
-        out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
+        out.attributeBoolean(null, ATTR_REALACTIVITY_SUSPENDED, realActivitySuspended);
         if (origActivity != null) {
             out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
         }
@@ -4509,37 +4511,36 @@
         if (mWindowLayoutAffinity != null) {
             out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
         }
-        out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
-        out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
-        out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
-        out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
-        out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
-        out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
-        out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
-        out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
+        out.attributeBoolean(null, ATTR_ROOTHASRESET, rootWasReset);
+        out.attributeBoolean(null, ATTR_AUTOREMOVERECENTS, autoRemoveRecents);
+        out.attributeBoolean(null, ATTR_ASKEDCOMPATMODE, askedCompatMode);
+        out.attributeInt(null, ATTR_USERID, mUserId);
+        out.attributeBoolean(null, ATTR_USER_SETUP_COMPLETE, mUserSetupComplete);
+        out.attributeInt(null, ATTR_EFFECTIVE_UID, effectiveUid);
+        out.attributeLong(null, ATTR_LASTTIMEMOVED, mLastTimeMoved);
+        out.attributeBoolean(null, ATTR_NEVERRELINQUISH, mNeverRelinquishIdentity);
         if (lastDescription != null) {
             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
         }
         if (getTaskDescription() != null) {
             getTaskDescription().saveToXml(out);
         }
-        out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
-        out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
-        out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
-        out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
+        out.attributeInt(null, ATTR_TASK_AFFILIATION, mAffiliatedTaskId);
+        out.attributeInt(null, ATTR_PREV_AFFILIATION, mPrevAffiliateTaskId);
+        out.attributeInt(null, ATTR_NEXT_AFFILIATION, mNextAffiliateTaskId);
+        out.attributeInt(null, ATTR_CALLING_UID, mCallingUid);
         out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
         out.attribute(null, ATTR_CALLING_FEATURE_ID,
                 mCallingFeatureId == null ? "" : mCallingFeatureId);
-        out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
-        out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
-                String.valueOf(mSupportsPictureInPicture));
+        out.attributeInt(null, ATTR_RESIZE_MODE, mResizeMode);
+        out.attributeBoolean(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, mSupportsPictureInPicture);
         if (mLastNonFullscreenBounds != null) {
             out.attribute(
                     null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
         }
-        out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
-        out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
-        out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
+        out.attributeInt(null, ATTR_MIN_WIDTH, mMinWidth);
+        out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight);
+        out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION);
 
         if (affinityIntent != null) {
             out.startTag(null, TAG_AFFINITYINTENT);
@@ -4564,7 +4565,7 @@
     }
 
     private static boolean saveActivityToXml(
-            ActivityRecord r, ActivityRecord first, XmlSerializer out) {
+            ActivityRecord r, ActivityRecord first, TypedXmlSerializer out) {
         if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
                 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
                 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
@@ -4583,7 +4584,7 @@
         }
     }
 
-    static Task restoreFromXml(XmlPullParser in, ActivityTaskSupervisor taskSupervisor)
+    static Task restoreFromXml(TypedXmlPullParser in, ActivityTaskSupervisor taskSupervisor)
             throws IOException, XmlPullParserException {
         Intent intent = null;
         Intent affinityIntent = null;
@@ -5764,6 +5765,10 @@
                     starting, configChanges, preserveWindows, notifyClients, userLeaving),
                     true /* traverseTopToBottom */);
 
+            // Notify WM shell that task visibilities may have changed
+            forAllTasks(task -> task.dispatchTaskInfoChangedIfNeeded(/* force */ false),
+                    true /* traverseTopToBottom */);
+
             if (mTranslucentActivityWaiting != null &&
                     mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
                 // Nothing is getting drawn or everything was already visible, don't wait for
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index c02e7ad..81b8200 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -157,12 +157,24 @@
      */
     private int mLastLeafTaskToFrontId;
 
+    /**
+     * Whether this TaskDisplayArea was created by a {@link android.window.DisplayAreaOrganizer}.
+     * If {@code true}, this will be removed when the organizer is unregistered.
+     */
+    final boolean mCreatedByOrganizer;
+
     TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
             int displayAreaFeature) {
+        this(displayContent, service, name, displayAreaFeature, false /* createdByOrganizer */);
+    }
+
+    TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
+            int displayAreaFeature, boolean createdByOrganizer) {
         super(service, Type.ANY, name, displayAreaFeature);
         mDisplayContent = displayContent;
         mRootWindowContainer = service.mRoot;
         mAtmService = service.mAtmService;
+        mCreatedByOrganizer = createdByOrganizer;
     }
 
     /**
@@ -1914,6 +1926,11 @@
     }
 
     @Override
+    TaskDisplayArea asTaskDisplayArea() {
+        return this;
+    }
+
+    @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         pw.println(prefix + "TaskDisplayArea " + getName());
         final String doublePrefix = prefix + "  ";
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 6dc957c..8b2fa52 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -35,6 +35,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.server.wm.ActivityStarter.Request;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -99,23 +100,25 @@
             ActivityRecord source, ActivityOptions options, LaunchParams currentParams,
             LaunchParams outParams) {
         return onCalculate(task, layout, activity, source, options, PHASE_BOUNDS, currentParams,
-                outParams);
+                outParams, null);
     }
 
     @Override
-    public int onCalculate(Task task, ActivityInfo.WindowLayout layout,
-                           ActivityRecord activity, ActivityRecord source, ActivityOptions options,
-                           int phase, LaunchParams currentParams, LaunchParams outParams) {
+    public int onCalculate(@Nullable Task task, @NonNull ActivityInfo.WindowLayout layout,
+            @NonNull ActivityRecord activity, @Nullable ActivityRecord source,
+            ActivityOptions options, int phase, LaunchParams currentParams, LaunchParams outParams,
+            @Nullable Request request) {
         initLogBuilder(task, activity);
         final int result = calculate(task, layout, activity, source, options, phase, currentParams,
-                outParams);
+                outParams, request);
         outputLog();
         return result;
     }
 
-    private int calculate(Task task, ActivityInfo.WindowLayout layout,
-            ActivityRecord activity, ActivityRecord source, ActivityOptions options, int phase,
-            LaunchParams currentParams, LaunchParams outParams) {
+    private int calculate(@Nullable Task task, @NonNull ActivityInfo.WindowLayout layout,
+            @NonNull ActivityRecord activity, @Nullable ActivityRecord source,
+            ActivityOptions options, int phase, LaunchParams currentParams, LaunchParams outParams,
+            @Nullable Request request) {
         final ActivityRecord root;
         if (task != null) {
             root = task.getRootActivity() == null ? activity : task.getRootActivity();
@@ -138,7 +141,7 @@
 
         // STEP 1: Determine the display area to launch the activity/task.
         final TaskDisplayArea taskDisplayArea = getPreferredLaunchTaskDisplayArea(task,
-                options, source, currentParams);
+                options, source, currentParams, activity, request);
         outParams.mPreferredTaskDisplayArea = taskDisplayArea;
         // TODO(b/152116619): Update the usages of display to use taskDisplayArea below.
         final DisplayContent display = taskDisplayArea.mDisplayContent;
@@ -298,7 +301,8 @@
     }
 
     private TaskDisplayArea getPreferredLaunchTaskDisplayArea(@Nullable Task task,
-            @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) {
+            @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams,
+            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
         TaskDisplayArea taskDisplayArea = null;
 
         final WindowContainerToken optionLaunchTaskDisplayAreaToken = options != null
@@ -369,7 +373,7 @@
             taskDisplayArea = currentParams.mPreferredTaskDisplayArea;
         }
 
-        // Fallback to default display if the device didn't declare support for multi-display
+        // Re-route to default display if the device didn't declare support for multi-display
         if (taskDisplayArea != null && !mSupervisor.mService.mSupportsMultiDisplay
                 && taskDisplayArea.getDisplayId() != DEFAULT_DISPLAY) {
             taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
@@ -377,7 +381,53 @@
 
         return (taskDisplayArea != null)
                 ? taskDisplayArea
-                : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+                : getFallbackDisplayAreaForActivity(activityRecord, request);
+    }
+
+    /**
+     * Calculates the default {@link TaskDisplayArea} for a task. We attempt to put the activity
+     * within the same display area if possible. The strategy is to find the display in the
+     * following order:
+     *
+     * <ol>
+     *     <li>The display area of the top activity from the launching process will be used</li>
+     *     <li>The display area of the top activity from the real launching process will be used
+     *     </li>
+     *     <li>Default display area from the associated root window container.</li>
+     * </ol>
+     * @param activityRecord the activity being started
+     * @param request optional {@link Request} made to start the activity record
+     * @return {@link TaskDisplayArea} to house the task
+     */
+    private TaskDisplayArea getFallbackDisplayAreaForActivity(
+            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+
+        WindowProcessController controllerFromLaunchingRecord = mSupervisor.mService
+                .getProcessController(activityRecord.launchedFromPid,
+                        activityRecord.launchedFromUid);
+        final TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null
+                ? null : controllerFromLaunchingRecord.getTopActivityDisplayArea();
+        if (displayAreaForLaunchingRecord != null) {
+            return displayAreaForLaunchingRecord;
+        }
+
+        WindowProcessController controllerFromProcess = mSupervisor.mService.getProcessController(
+                activityRecord.getProcessName(), activityRecord.getUid());
+        final TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null
+                : controllerFromProcess.getTopActivityDisplayArea();
+        if (displayAreaForRecord != null) {
+            return displayAreaForRecord;
+        }
+
+        WindowProcessController controllerFromRequest = request == null ? null : mSupervisor
+                .mService.getProcessController(request.realCallingPid, request.realCallingUid);
+        final TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null
+                : controllerFromRequest.getTopActivityDisplayArea();
+        if (displayAreaFromSourceProcess != null) {
+            return displayAreaFromSourceProcess;
+        }
+
+        return mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
     }
 
     private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index c976bc2..855dd7e 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -30,26 +30,28 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
-import java.io.StringWriter;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -305,12 +307,9 @@
                 continue;
             }
 
-            BufferedReader reader = null;
             boolean deleteFile = false;
-            try {
-                reader = new BufferedReader(new FileReader(taskFile));
-                final XmlPullParser in = Xml.newPullParser();
-                in.setInput(reader);
+            try (InputStream is = new FileInputStream(taskFile)) {
+                final TypedXmlPullParser in = Xml.resolvePullParser(is);
 
                 int event;
                 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
@@ -360,7 +359,6 @@
                 Slog.e(TAG, "Failing file: " + fileToString(taskFile));
                 deleteFile = true;
             } finally {
-                IoUtils.closeQuietly(reader);
                 if (deleteFile) {
                     if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName());
                     taskFile.delete();
@@ -513,11 +511,10 @@
             mService = service;
         }
 
-        private StringWriter saveToXml(Task task) throws Exception {
+        private byte[] saveToXml(Task task) throws Exception {
             if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
-            final XmlSerializer xmlSerializer = new FastXmlSerializer();
-            StringWriter stringWriter = new StringWriter();
-            xmlSerializer.setOutput(stringWriter);
+            final ByteArrayOutputStream os = new ByteArrayOutputStream();
+            final TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(os);
 
             if (DEBUG) {
                 xmlSerializer.setFeature(
@@ -534,13 +531,13 @@
             xmlSerializer.endDocument();
             xmlSerializer.flush();
 
-            return stringWriter;
+            return os.toByteArray();
         }
 
         @Override
         public void process() {
             // Write out one task.
-            StringWriter stringWriter = null;
+            byte[] data = null;
             Task task = mTask;
             if (DEBUG) Slog.d(TAG, "Writing task=" + task);
             synchronized (mService.mGlobalLock) {
@@ -548,12 +545,12 @@
                     // Still there.
                     try {
                         if (DEBUG) Slog.d(TAG, "Saving task=" + task);
-                        stringWriter = saveToXml(task);
+                        data = saveToXml(task);
                     } catch (Exception e) {
                     }
                 }
             }
-            if (stringWriter != null) {
+            if (data != null) {
                 // Write out xml file while not holding mService lock.
                 FileOutputStream file = null;
                 AtomicFile atomicFile = null;
@@ -567,8 +564,7 @@
                     atomicFile = new AtomicFile(new File(userTasksDir,
                             String.valueOf(task.mTaskId) + TASK_FILENAME_SUFFIX));
                     file = atomicFile.startWrite();
-                    file.write(stringWriter.toString().getBytes());
-                    file.write('\n');
+                    file.write(data);
                     atomicFile.finishWrite(file);
                 } catch (IOException e) {
                     if (file != null) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 341694d..0cdd055 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -26,6 +26,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
@@ -46,7 +47,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.Set;
 
 /**
  * Represents a logical transition.
@@ -91,13 +91,24 @@
     private final BLASTSyncEngine mSyncEngine;
 
     /**
+     * This is a leash to put animating surfaces into flatly without clipping/ordering issues. It
+     * is a child of all the targets' shared ancestor.
+     */
+    private SurfaceControl mRootLeash = null;
+
+    /**
      * Contains change infos for both participants and all ancestors. We have to track ancestors
      * because they are all promotion candidates and thus we need their start-states
      * to be captured.
      */
     final ArrayMap<WindowContainer, ChangeInfo> mChanges = new ArrayMap<>();
 
+    /** The collected participants in the transition. */
     final ArraySet<WindowContainer> mParticipants = new ArraySet<>();
+
+    /** The final animation targets derived from participants after promotion. */
+    private ArraySet<WindowContainer> mTargets = null;
+
     private @TransitionState int mState = STATE_COLLECTING;
     private boolean mReadyCalled = false;
 
@@ -190,6 +201,42 @@
         if (mState < STATE_PLAYING) {
             throw new IllegalStateException("Can't finish a non-playing transition " + mSyncId);
         }
+        final Point tmpPos = new Point();
+        // usually only size 1
+        final ArraySet<DisplayContent> displays = new ArraySet<>();
+        // Immediately apply all surface reparents, don't wait for pending/sync/etc.
+        SurfaceControl.Transaction t = mController.mAtm.mWindowManager.mTransactionFactory.get();
+        for (int i = mTargets.size() - 1; i >= 0; --i) {
+            final WindowContainer target = mTargets.valueAt(i);
+            if (target.getParent() != null) {
+                // Ensure surfaceControls are re-parented back into the hierarchy.
+                t.reparent(target.getSurfaceControl(), target.getParent().getSurfaceControl());
+                target.getRelativePosition(tmpPos);
+                t.setPosition(target.getSurfaceControl(), tmpPos.x, tmpPos.y);
+                displays.add(target.getDisplayContent());
+            }
+        }
+        // Need to update layers on ALL displays (for now) since they were all paused while
+        // the animation played.
+        for (int i = displays.size() - 1; i >= 0; --i) {
+            if (displays.valueAt(i) == null) continue;
+            displays.valueAt(i).assignChildLayers(t);
+        }
+        // Also pro-actively hide going-invisible activity surfaces in same transaction to
+        // prevent flickers due to reparenting and animation z-order mismatch.
+        for (int i = mParticipants.size() - 1; i >= 0; --i) {
+            final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
+            if (ar == null || ar.mVisibleRequested || !ar.isVisible()) continue;
+            t.hide(ar.getSurfaceControl());
+        }
+        if (mRootLeash.isValid()) {
+            t.remove(mRootLeash);
+        }
+        mRootLeash = null;
+        t.apply();
+        t.close();
+
+        // Commit all going-invisible containers
         for (int i = 0; i < mParticipants.size(); ++i) {
             final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
             if (ar == null || ar.mVisibleRequested) {
@@ -234,7 +281,11 @@
 
         mState = STATE_PLAYING;
         mController.moveToPlaying(this);
-        final TransitionInfo info = calculateTransitionInfo(mType, mParticipants, mChanges);
+
+        // Resolve the animating targets from the participants
+        mTargets = calculateTargets(mParticipants, mChanges);
+        final TransitionInfo info = calculateTransitionInfo(mType, mTargets, mChanges);
+        mRootLeash = info.getRootLeash();
 
         handleNonAppWindowsInTransition(displayId, mType, mFlags);
 
@@ -245,11 +296,14 @@
                 mController.getTransitionPlayer().onTransitionReady(this, info, transaction);
             } catch (RemoteException e) {
                 // If there's an exception when trying to send the mergedTransaction to the
-                // client, we should immediately apply it here so the transactions aren't lost.
+                // client, we should finish and apply it here so the transactions aren't lost.
                 transaction.apply();
+                finishTransition();
             }
         } else {
+            // No player registered, so just finish/apply immediately
             transaction.apply();
+            finishTransition();
         }
         mSyncId = -1;
     }
@@ -325,10 +379,12 @@
      *
      * @return {@code true} if transition in target can be promoted to its parent.
      */
-    private static boolean canPromote(
-            WindowContainer target, ArraySet<WindowContainer> topTargets) {
+    private static boolean canPromote(WindowContainer target, ArraySet<WindowContainer> topTargets,
+            ArrayMap<WindowContainer, ChangeInfo> changes) {
         final WindowContainer parent = target.getParent();
-        if (parent == null || !parent.canCreateRemoteAnimationTarget()) {
+        final ChangeInfo parentChanges = parent != null ? changes.get(parent) : null;
+        if (parent == null || !parent.canCreateRemoteAnimationTarget()
+                || parentChanges == null || !parentChanges.hasChanged(parent)) {
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "      SKIP: %s",
                     parent == null ? "no parent" : ("parent can't be target " + parent));
             return false;
@@ -394,14 +450,14 @@
         // Go through each target until we find one that can be promoted.
         for (WindowContainer targ : topTargets) {
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "    checking %s", targ);
-            if (!canPromote(targ, topTargets)) {
+            if (!canPromote(targ, topTargets, changes)) {
                 continue;
             }
-            final WindowContainer parent = targ.getParent();
             // No obstructions found to promotion, so promote
+            final WindowContainer parent = targ.getParent();
+            final ChangeInfo parentInfo = changes.get(parent);
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                     "      CAN PROMOTE: promoting to parent %s", parent);
-            final ChangeInfo parentInfo = changes.get(parent);
             targets.add(parent);
 
             // Go through all children of newly-promoted container and remove them from the
@@ -443,10 +499,9 @@
      * animation targets to higher level in the window hierarchy if possible.
      */
     @VisibleForTesting
-    static TransitionInfo calculateTransitionInfo(int type, Set<WindowContainer> participants,
+    @NonNull
+    static ArraySet<WindowContainer> calculateTargets(ArraySet<WindowContainer> participants,
             ArrayMap<WindowContainer, ChangeInfo> changes) {
-        final TransitionInfo out = new TransitionInfo(type);
-
         ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                 "Start calculating TransitionInfo based on participants: %s", participants);
 
@@ -470,6 +525,9 @@
             // Search through ancestors to find the top-most participant (if one exists)
             WindowContainer topParent = null;
             tmpList.clear();
+            if (reportIfNotTop(wc)) {
+                tmpList.add(wc);
+            }
             for (WindowContainer p = wc.getParent(); p != null; p = p.getParent()) {
                 if (participants.contains(p)) {
                     topParent = p;
@@ -479,8 +537,8 @@
                 }
             }
             if (topParent != null) {
-                // There was an ancestor participant, so don't add wc to targets. However, continue
-                // to add any always-report parents along the way.
+                // There was an ancestor participant, so don't add wc to targets unless always-
+                // report. Similarly, add any always-report parents along the way.
                 for (int i = 0; i < tmpList.size(); ++i) {
                     targets.add(tmpList.get(i));
                     final ChangeInfo info = changes.get(tmpList.get(i));
@@ -508,10 +566,70 @@
         while (tryPromote(topTargets, targets, changes)) {
             // Empty on purpose
         }
+        return targets;
+    }
 
-        // Convert all the resolved ChangeInfos into a TransactionInfo object.
-        for (int i = targets.size() - 1; i >= 0; --i) {
-            final WindowContainer target = targets.valueAt(i);
+    /** Add any of `members` within `root` to `out` in top-to-bottom z-order. */
+    private static void addMembersInOrder(WindowContainer root, ArraySet<WindowContainer> members,
+            ArrayList<WindowContainer> out) {
+        for (int i = root.getChildCount() - 1; i >= 0; --i) {
+            final WindowContainer child = root.getChildAt(i);
+            addMembersInOrder(child, members, out);
+            if (members.contains(child)) {
+                out.add(child);
+            }
+        }
+    }
+
+    /**
+     * Construct a TransitionInfo object from a set of targets and changes. Also populates the
+     * root surface.
+     */
+    @VisibleForTesting
+    @NonNull
+    static TransitionInfo calculateTransitionInfo(int type, ArraySet<WindowContainer> targets,
+            ArrayMap<WindowContainer, ChangeInfo> changes) {
+        final TransitionInfo out = new TransitionInfo(type);
+        if (targets.isEmpty()) {
+            out.setRootLeash(new SurfaceControl(), 0, 0);
+            return out;
+        }
+
+        // Find the top-most shared ancestor
+        WindowContainer ancestor = targets.valueAt(0).getParent();
+        // Go up ancestor parent chain until all topTargets are descendants.
+        ancestorLoop:
+        while (ancestor != null) {
+            for (int i = 1; i < targets.size(); ++i) {
+                if (!targets.valueAt(i).isDescendantOf(ancestor)) {
+                    ancestor = ancestor.getParent();
+                    continue ancestorLoop;
+                }
+            }
+            break;
+        }
+
+        // Sort targets top-to-bottom in Z.
+        ArrayList<WindowContainer> sortedTargets = new ArrayList<>();
+        addMembersInOrder(ancestor, targets, sortedTargets);
+
+        // make leash based on highest (z-order) direct child of ancestor with a participant.
+        WindowContainer leashReference = sortedTargets.get(0);
+        while (leashReference.getParent() != ancestor) {
+            leashReference = leashReference.getParent();
+        }
+        final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
+                "Transition Root: " + leashReference.getName()).build();
+        SurfaceControl.Transaction t = ancestor.mWmService.mTransactionFactory.get();
+        t.setLayer(rootLeash, leashReference.getLastLayer());
+        t.apply();
+        t.close();
+        out.setRootLeash(rootLeash, ancestor.getBounds().left, ancestor.getBounds().top);
+
+        // Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
+        final int count = sortedTargets.size();
+        for (int i = 0; i < count; ++i) {
+            final WindowContainer target = sortedTargets.get(i);
             final ChangeInfo info = changes.get(target);
             final TransitionInfo.Change change = new TransitionInfo.Change(
                     target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()
@@ -520,8 +638,10 @@
                 change.setParent(info.mParent.mRemoteToken.toWindowContainerToken());
             }
             change.setMode(info.getTransitMode(target));
-            change.setStartBounds(info.mAbsoluteBounds);
-            change.setEndBounds(target.getBounds());
+            change.setStartAbsBounds(info.mAbsoluteBounds);
+            change.setEndAbsBounds(target.getBounds());
+            change.setEndRelOffset(target.getBounds().left - target.getParent().getBounds().left,
+                    target.getBounds().top - target.getParent().getBounds().top);
             out.addChange(change);
         }
 
@@ -543,23 +663,26 @@
         // before change state
         boolean mVisible;
         int mWindowingMode;
-        Rect mAbsoluteBounds;
+        final Rect mAbsoluteBounds = new Rect();
 
         ChangeInfo(@NonNull WindowContainer origState) {
             mVisible = origState.isVisibleRequested();
             mWindowingMode = origState.getWindowingMode();
-            mAbsoluteBounds = origState.getBounds();
+            mAbsoluteBounds.set(origState.getBounds());
         }
 
         @VisibleForTesting
         ChangeInfo(boolean visible, boolean existChange) {
             mVisible = visible;
-            mAbsoluteBounds = new Rect();
             mExistenceChanged = existChange;
         }
 
         boolean hasChanged(@NonNull WindowContainer newState) {
-            return newState.isVisibleRequested() != mVisible
+            // If it's invisible and hasn't changed visibility, always return false since even if
+            // something changed, it wouldn't be a visible change.
+            final boolean currVisible = newState.isVisibleRequested();
+            if (currVisible == mVisible && !mVisible) return false;
+            return currVisible != mVisible
                     // if mWindowingMode is 0, this container wasn't attached at collect time, so
                     // assume no change in windowing-mode.
                     || (mWindowingMode != 0 && newState.getWindowingMode() != mWindowingMode)
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 890ae8f2..2f5d10a 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -109,10 +109,18 @@
         return mCollectingTransition != null;
     }
 
+    /**
+     * @return {@code true} if transition is actively playing. This is not necessarily {@code true}
+     * during collection.
+     */
+    boolean isPlaying() {
+        return !mPlayingTransitions.isEmpty();
+    }
+
     /** @return {@code true} if a transition is running */
     boolean inTransition() {
         // TODO(shell-transitions): eventually properly support multiple
-        return mCollectingTransition != null || !mPlayingTransitions.isEmpty();
+        return isCollecting() || isPlaying();
     }
 
     /** @return {@code true} if wc is in a participant subtree */
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 4574be7..cf6468d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1139,18 +1139,15 @@
      * Called when this container or one of its descendants changed its requested orientation, and
      * wants this container to handle it or pass it to its parent.
      *
-     * @param freezeDisplayToken freeze this app window token if display needs to freeze
      * @param requestingContainer the container which orientation request has changed
      * @return {@code true} if handled; {@code false} otherwise.
      */
-    boolean onDescendantOrientationChanged(@Nullable IBinder freezeDisplayToken,
-            @Nullable WindowContainer requestingContainer) {
+    boolean onDescendantOrientationChanged(@Nullable WindowContainer requestingContainer) {
         final WindowContainer parent = getParent();
         if (parent == null) {
             return false;
         }
-        return parent.onDescendantOrientationChanged(freezeDisplayToken,
-                requestingContainer);
+        return parent.onDescendantOrientationChanged(requestingContainer);
     }
 
     /**
@@ -1224,14 +1221,13 @@
     }
 
     /**
-     * Calls {@link #setOrientation(int, IBinder, ActivityRecord)} with {@code null} to the last 2
+     * Calls {@link #setOrientation(int, IBinder, WindowContainer)} with {@code null} to the last 2
      * parameters.
      *
      * @param orientation the specified orientation.
      */
     void setOrientation(int orientation) {
-        setOrientation(orientation, null /* freezeDisplayToken */,
-                null /* ActivityRecord */);
+        setOrientation(orientation, null /* requestingContainer */);
     }
 
     /**
@@ -1240,14 +1236,10 @@
      *
      * @param orientation the specified orientation. Needs to be one of {@link
      *      android.content.pm.ActivityInfo.ScreenOrientation}.
-     * @param freezeDisplayToken uses this token to freeze display if orientation change is not
-     *                           done. Display will not be frozen if this is {@code null}, which
-     *                           should only happen in tests.
      * @param requestingContainer the container which orientation request has changed. Mostly used
      *                            to ensure it gets correct configuration.
      */
-    void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
-            @Nullable WindowContainer requestingContainer) {
+    void setOrientation(int orientation, @Nullable WindowContainer requestingContainer) {
         if (mOrientation == orientation) {
             return;
         }
@@ -1259,7 +1251,7 @@
                 // Resolve the requested orientation.
                 onConfigurationChanged(parent.getConfiguration());
             }
-            onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
+            onDescendantOrientationChanged(requestingContainer);
         }
     }
 
@@ -1814,7 +1806,7 @@
     /**
      * For all {@link TaskDisplayArea} at or below this container call the callback.
      * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
-     *                  returns {@code true}.
+     *                 returns {@code true}.
      * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
      *                            terms of z-order, else from bottom-to-top.
      * @return {@code true} if the search ended before we reached the end of the hierarchy due to
@@ -1837,7 +1829,7 @@
      * For all {@link TaskDisplayArea} at or below this container call the callback. Traverses from
      * top to bottom in terms of z-order.
      * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
-     *                  returns {@code true}.
+     *                 returns {@code true}.
      * @return {@code true} if the search ended before we reached the end of the hierarchy due to
      *         callback returning {@code true}.
      */
@@ -1873,7 +1865,7 @@
      * Performs a reduction on all {@link TaskDisplayArea} at or below this container, using the
      * provided initial value and an accumulation function, and returns the reduced value.
      * @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result
-     *                 from the previous call.
+     *                    from the previous call.
      * @param initValue The initial value to pass to the accumulating function with the first
      *                  {@link TaskDisplayArea}.
      * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
@@ -1899,7 +1891,7 @@
      * provided initial value and an accumulation function, and returns the reduced value. Traverses
      * from top to bottom in terms of z-order.
      * @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result
-     *                 from the previous call.
+     *                    from the previous call.
      * @param initValue The initial value to pass to the accumulating function with the first
      *                  {@link TaskDisplayArea}.
      * @return the accumulative result.
@@ -1912,9 +1904,29 @@
 
     /**
      * Finds the first non {@code null} return value from calling the callback on all
+     * {@link DisplayArea} at or below this container. Traverses from top to bottom in terms of
+     * z-order.
+     * @param callback Applies on each {@link DisplayArea} found and stops the search if it
+     *                 returns non {@code null}.
+     * @return the first returned object that is not {@code null}. Returns {@code null} if not
+     *         found.
+     */
+    @Nullable
+    <R> R getItemFromDisplayAreas(Function<DisplayArea, R> callback) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            R result = (R) mChildren.get(i).getItemFromDisplayAreas(callback);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds the first non {@code null} return value from calling the callback on all
      * {@link TaskDisplayArea} at or below this container.
      * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
-     *                  returns non {@code null}.
+     *                 returns non {@code null}.
      * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
      *                            terms of z-order, else from bottom-to-top.
      * @return the first returned object that is not {@code null}. Returns {@code null} if not
@@ -1941,7 +1953,7 @@
      * {@link TaskDisplayArea} at or below this container. Traverses from top to bottom in terms of
      * z-order.
      * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
-     *                  returns non {@code null}.
+     *                 returns non {@code null}.
      * @return the first returned object that is not {@code null}. Returns {@code null} if not
      *         found.
      */
@@ -2069,6 +2081,9 @@
     }
 
     void assignLayer(Transaction t, int layer) {
+        // Don't assign layers while a transition animation is playing
+        // TODO(b/173528115): establish robust best-practices around z-order fighting.
+        if (mWmService.mAtmService.getTransitionController().isPlaying()) return;
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
         if (mSurfaceControl != null && changed) {
             setLayer(t, layer);
@@ -2093,6 +2108,10 @@
         mSurfaceAnimator.setLayer(t, layer);
     }
 
+    int getLastLayer() {
+        return mLastLayer;
+    }
+
     protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
 
         // Route through surface animator to accommodate that our surface control might be
@@ -2884,6 +2903,16 @@
         return null;
     }
 
+    /** Cheap way of doing cast and instanceof. */
+    RootDisplayArea asRootDisplayArea() {
+        return null;
+    }
+
+    /** Cheap way of doing cast and instanceof. */
+    TaskDisplayArea asTaskDisplayArea() {
+        return null;
+    }
+
     /**
      * @return {@code true} if window container is manage by a
      *          {@link android.window.WindowOrganizer}
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index b0c5dbc..a5ebf9a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -23,7 +23,7 @@
 import android.provider.DeviceConfig;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.wm.utils.DeviceConfigInterface;
+import com.android.server.utils.DeviceConfigInterface;
 
 import java.io.PrintWriter;
 import java.util.Objects;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index d082778..a3a9eb7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -30,6 +30,7 @@
 import android.view.InputChannel;
 import android.view.MagnificationSpec;
 import android.view.WindowInfo;
+import android.view.WindowManager.DisplayImePolicy;
 
 import com.android.internal.policy.KeyInterceptionInfo;
 import com.android.server.input.InputManagerService;
@@ -506,12 +507,12 @@
     public abstract boolean shouldShowSystemDecorOnDisplay(int displayId);
 
     /**
-     * Indicates that the display should show IME.
+     * Indicates the policy for how the display should show IME.
      *
      * @param displayId The id of the display.
-     * @return {@code true} if the display should show IME when an input field become focused on it.
+     * @return The policy for how the display should show IME.
      */
-    public abstract boolean shouldShowIme(int displayId);
+    public abstract @DisplayImePolicy int getDisplayImePolicy(int displayId);
 
     /**
      * Show IME on imeTargetWindow once IME has finished layout.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 580c088..25049ae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -48,6 +48,7 @@
 import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -198,6 +199,7 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.service.attestation.ImpressionToken;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
 import android.sysprop.SurfaceFlingerProperties;
@@ -255,6 +257,7 @@
 import android.view.WindowContentFrameStats;
 import android.view.WindowInsets;
 import android.view.WindowManager;
+import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.RemoveContentMode;
 import android.view.WindowManagerGlobal;
@@ -286,8 +289,8 @@
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.power.ShutdownThread;
+import com.android.server.utils.DeviceConfigInterface;
 import com.android.server.utils.PriorityDump;
-import com.android.server.wm.utils.DeviceConfigInterface;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
@@ -765,6 +768,8 @@
     final EmbeddedWindowController mEmbeddedWindowController;
     final AnrController mAnrController;
 
+    private final ImpressionAttestationController mImpressionAttestationController;
+
     @VisibleForTesting
     final class SettingsObserver extends ContentObserver {
         private final Uri mDisplayInversionEnabledUri =
@@ -1365,6 +1370,7 @@
         mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
                 mContext.getResources());
 
+        mImpressionAttestationController = new ImpressionAttestationController(mContext);
         setGlobalShadowSettings();
         mAnrController = new AnrController(this);
         mStartingSurfaceController = new StartingSurfaceController(this);
@@ -1625,7 +1631,7 @@
             }
 
             final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
-            displayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
+            displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
             win.updateRequestedVisibility(requestedVisibility);
 
             res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
@@ -2195,7 +2201,7 @@
             int flagChanges = 0;
             int privateFlagChanges = 0;
             if (attrs != null) {
-                displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
+                displayPolicy.adjustWindowParamsLw(win, attrs);
                 win.mToken.adjustWindowParams(win, attrs);
                 int disableFlags =
                         (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility) & DISABLE_MASK;
@@ -7245,28 +7251,25 @@
     }
 
     @Override
-    public boolean shouldShowIme(int displayId) {
-        if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "shouldShowIme()")) {
+    public @DisplayImePolicy int getDisplayImePolicy(int displayId) {
+        if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "getDisplayImePolicy()")) {
             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
         }
-        boolean show;
         final DisplayContent dc = mRoot.getDisplayContent(displayId);
         if (dc == null) {
             ProtoLog.w(WM_ERROR,
-                    "Attempted to get IME flag of a display that does not exist: %d",
+                    "Attempted to get IME policy of a display that does not exist: %d",
                     displayId);
-            return false;
+            return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
         }
         synchronized (mGlobalLock) {
-            show = dc.canShowIme();
+            return dc.getImePolicy();
         }
-
-        return show;
     }
 
     @Override
-    public void setShouldShowIme(int displayId, boolean shouldShow) {
-        if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowIme()")) {
+    public void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) {
+        if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setDisplayImePolicy()")) {
             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
         }
         final long origId = Binder.clearCallingIdentity();
@@ -7274,16 +7277,16 @@
             synchronized (mGlobalLock) {
                 final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
                 if (displayContent == null) {
-                    ProtoLog.w(WM_ERROR, "Attempted to set IME flag to a display that does not "
-                            + "exist: %d", displayId);
+                    ProtoLog.w(WM_ERROR, "Attempted to set IME policy to a display"
+                            + " that does not exist: %d", displayId);
                     return;
                 }
                 if (!displayContent.isTrusted()) {
-                    throw new SecurityException("Attempted to set IME flag to an untrusted "
+                    throw new SecurityException("Attempted to set IME policy to an untrusted "
                             + "virtual display: " + displayId);
                 }
 
-                mDisplayWindowSettings.setShouldShowImeLocked(displayContent, shouldShow);
+                mDisplayWindowSettings.setDisplayImePolicy(displayContent, imePolicy);
 
                 displayContent.reconfigureDisplayLocked();
             }
@@ -7765,9 +7768,9 @@
         }
 
         @Override
-        public boolean shouldShowIme(int displayId) {
+        public @DisplayImePolicy int getDisplayImePolicy(int displayId) {
             synchronized (mGlobalLock) {
-                return WindowManagerService.this.shouldShowIme(displayId);
+                return WindowManagerService.this.getDisplayImePolicy(displayId);
             }
         }
 
@@ -8429,4 +8432,64 @@
             SystemClock.sleep(durationMs);
         }
     }
+
+    @Override
+    public String[] getSupportedImpressionAlgorithms() {
+        return mImpressionAttestationController.getSupportedImpressionAlgorithms();
+    }
+
+    @Override
+    public boolean verifyImpressionToken(ImpressionToken impressionToken) {
+        return mImpressionAttestationController.verifyImpressionToken(impressionToken);
+    }
+
+    ImpressionToken generateImpressionToken(Session session, IWindow window,
+            Rect boundsInWindow, String hashAlgorithm) {
+        final SurfaceControl displaySurfaceControl;
+        final Rect boundsInDisplay = new Rect(boundsInWindow);
+        synchronized (mGlobalLock) {
+            final WindowState win = windowForClientLocked(session, window, false);
+            if (win == null) {
+                Slog.w(TAG, "Failed to generate impression token. Invalid window");
+                return null;
+            }
+
+            DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent == null) {
+                Slog.w(TAG, "Failed to generate impression token. Window is not on a display");
+                return null;
+            }
+
+            displaySurfaceControl = displayContent.getSurfaceControl();
+            mImpressionAttestationController.calculateImpressionTokenBoundsLocked(win,
+                    boundsInWindow, boundsInDisplay);
+
+            if (boundsInDisplay.isEmpty()) {
+                Slog.w(TAG, "Failed to generate impression token. Bounds are not on screen");
+                return null;
+            }
+        }
+
+        // A screenshot of the entire display is taken rather than just the window. This is
+        // because if we take a screenshot of the window, it will not include content that might
+        // be covering it with the same uid. We want to make sure we include content that's
+        // covering to ensure we get as close as possible to what the user sees
+        final int uid = session.mUid;
+        SurfaceControl.LayerCaptureArgs args =
+                new SurfaceControl.LayerCaptureArgs.Builder(displaySurfaceControl)
+                        .setUid(uid)
+                        .setSourceCrop(boundsInDisplay)
+                        .build();
+
+        SurfaceControl.ScreenshotHardwareBuffer screenshotHardwareBuffer =
+                SurfaceControl.captureLayers(args);
+        if (screenshotHardwareBuffer == null
+                || screenshotHardwareBuffer.getHardwareBuffer() == null) {
+            Slog.w(TAG, "Failed to generate impression token. Failed to take screenshot");
+            return null;
+        }
+
+        return mImpressionAttestationController.generateImpressionToken(
+                screenshotHardwareBuffer.getHardwareBuffer(), boundsInWindow, hashAlgorithm);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c55f059..8f8fea3 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -730,6 +730,28 @@
         return mHasActivities || mHasRecentTasks;
     }
 
+    @Nullable
+    TaskDisplayArea getTopActivityDisplayArea() {
+        if (mActivities.isEmpty()) {
+            return null;
+        }
+
+        final int lastIndex = mActivities.size() - 1;
+        ActivityRecord topRecord = mActivities.get(lastIndex);
+        TaskDisplayArea displayArea = topRecord.getDisplayArea();
+
+        for (int index = lastIndex - 1; index >= 0; --index) {
+            ActivityRecord nextRecord = mActivities.get(index);
+            TaskDisplayArea nextDisplayArea = nextRecord.getDisplayArea();
+            if (nextRecord.compareTo(topRecord) > 0 && nextDisplayArea != null) {
+                topRecord = nextRecord;
+                displayArea = nextDisplayArea;
+            }
+        }
+
+        return displayArea;
+    }
+
     private boolean hasActivityInVisibleTask() {
         for (int i = mActivities.size() - 1; i >= 0; --i) {
             Task task = mActivities.get(i).getTask();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0a8ff4d..c318fad 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -127,6 +127,7 @@
 import static com.android.server.wm.MoveAnimationSpecProto.DURATION_MS;
 import static com.android.server.wm.MoveAnimationSpecProto.FROM;
 import static com.android.server.wm.MoveAnimationSpecProto.TO;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -972,6 +973,9 @@
         if (WindowManager.LayoutParams.isSystemAlertWindowType(mAttrs.type)) {
             return TouchOcclusionMode.USE_OPACITY;
         }
+        if (isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_ALL)) {
+            return TouchOcclusionMode.USE_OPACITY;
+        }
         return TouchOcclusionMode.BLOCK_UNTRUSTED;
     }
 
@@ -5267,6 +5271,12 @@
         if (mSurfaceControl == null) {
             return;
         }
+        if (mWmService.mWindowPlacerLocked.isLayoutDeferred() || isGoneForLayout()) {
+            // Since this relies on mWindowFrames, changes made while layout is deferred are
+            // likely to be invalid. Similarly, if it's goneForLayout, mWindowFrames may not be
+            // up-to-date and thus can't be relied on.
+            return;
+        }
 
         transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
                 mSurfacePosition);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index da2c005..6da9517 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -53,8 +53,8 @@
         "com_android_server_UsbDescriptorParser.cpp",
         "com_android_server_UsbMidiDevice.cpp",
         "com_android_server_UsbHostManager.cpp",
+        "com_android_server_vibrator_VibratorController.cpp",
         "com_android_server_VibratorManagerService.cpp",
-        "com_android_server_VibratorService.cpp",
         "com_android_server_PersistentDataBlockService.cpp",
         "com_android_server_am_CachedAppOptimizer.cpp",
         "com_android_server_am_LowMemDetector.cpp",
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 4c017f5..6f74885 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -2,8 +2,8 @@
 per-file com_android_server_lights_LightsService.cpp = michaelwr@google.com, santoscordon@google.com
 
 # Haptics
+per-file com_android_server_vibrator_VibratorController.cpp = michaelwr@google.com
 per-file com_android_server_VibratorManagerService.cpp = michaelwr@google.com
-per-file com_android_server_VibratorService.cpp = michaelwr@google.com
 
 # Input
 per-file com_android_server_input_InputManagerService.cpp = michaelwr@google.com, svv@google.com
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
deleted file mode 100644
index 9aca848..0000000
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VibratorService"
-
-#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include "android_runtime/AndroidRuntime.h"
-#include "core_jni_helpers.h"
-
-#include <utils/misc.h>
-#include <utils/Log.h>
-
-#include <inttypes.h>
-
-#include <vibratorservice/VibratorHalController.h>
-
-namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_1 = android::hardware::vibrator::V1_1;
-namespace V1_2 = android::hardware::vibrator::V1_2;
-namespace V1_3 = android::hardware::vibrator::V1_3;
-namespace aidl = android::hardware::vibrator;
-
-namespace android {
-
-static JavaVM* sJvm = nullptr;
-static jmethodID sMethodIdOnComplete;
-static struct {
-    jfieldID id;
-    jfieldID scale;
-    jfieldID delay;
-} sPrimitiveClassInfo;
-
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
-                static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
-                static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
-                static_cast<uint8_t>(aidl::EffectStrength::STRONG));
-
-static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
-                static_cast<uint8_t>(aidl::Effect::CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
-                static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
-                static_cast<uint8_t>(aidl::Effect::TICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
-                static_cast<uint8_t>(aidl::Effect::THUD));
-static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
-                static_cast<uint8_t>(aidl::Effect::POP));
-static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
-                static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
-                static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
-                static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
-                static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
-                static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
-
-class NativeVibratorService {
-public:
-    NativeVibratorService(JNIEnv* env, jobject callbackListener)
-          : mController(std::make_unique<vibrator::HalController>()),
-            mCallbackListener(env->NewGlobalRef(callbackListener)) {
-        LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
-                            "Unable to create global reference to vibration callback handler");
-    }
-
-    ~NativeVibratorService() {
-        auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
-        jniEnv->DeleteGlobalRef(mCallbackListener);
-    }
-
-    vibrator::HalController* controller() const { return mController.get(); }
-
-    std::function<void()> createCallback(jlong vibrationId) {
-        return [vibrationId, this]() {
-            auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
-            jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, vibrationId);
-        };
-    }
-
-private:
-    const std::unique_ptr<vibrator::HalController> mController;
-    const jobject mCallbackListener;
-};
-
-static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
-    aidl::CompositeEffect effect;
-    effect.primitive = static_cast<aidl::CompositePrimitive>(
-            env->GetIntField(primitive, sPrimitiveClassInfo.id));
-    effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale));
-    effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay));
-    return effect;
-}
-
-static void destroyNativeService(void* servicePtr) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service) {
-        delete service;
-    }
-}
-
-static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) {
-    std::unique_ptr<NativeVibratorService> service =
-            std::make_unique<NativeVibratorService>(env, callbackListener);
-    service->controller()->init();
-    return reinterpret_cast<jlong>(service.release());
-}
-
-static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
-    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
-}
-
-static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorExists failed because native service was not initialized");
-        return JNI_FALSE;
-    }
-    return service->controller()->ping().isOk() ? JNI_TRUE : JNI_FALSE;
-}
-
-static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong timeoutMs,
-                       jlong vibrationId) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorOn failed because native service was not initialized");
-        return;
-    }
-    auto callback = service->createCallback(vibrationId);
-    service->controller()->on(std::chrono::milliseconds(timeoutMs), callback);
-}
-
-static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorOff failed because native service was not initialized");
-        return;
-    }
-    service->controller()->off();
-}
-
-static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
-                                 jint amplitude) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorSetAmplitude failed because native service was not initialized");
-        return;
-    }
-    service->controller()->setAmplitude(static_cast<int32_t>(amplitude));
-}
-
-static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
-                                       jboolean enabled) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorSetExternalControl failed because native service was not initialized");
-        return;
-    }
-    service->controller()->setExternalControl(enabled);
-}
-
-static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorGetSupportedEffects failed because native service was not initialized");
-        return nullptr;
-    }
-    auto result = service->controller()->getSupportedEffects();
-    if (!result.isOk()) {
-        return nullptr;
-    }
-    std::vector<aidl::Effect> supportedEffects = result.value();
-    jintArray effects = env->NewIntArray(supportedEffects.size());
-    env->SetIntArrayRegion(effects, 0, supportedEffects.size(),
-                           reinterpret_cast<jint*>(supportedEffects.data()));
-    return effects;
-}
-
-static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorGetSupportedPrimitives failed because native service was not initialized");
-        return nullptr;
-    }
-    auto result = service->controller()->getSupportedPrimitives();
-    if (!result.isOk()) {
-        return nullptr;
-    }
-    std::vector<aidl::CompositePrimitive> supportedPrimitives = result.value();
-    jintArray primitives = env->NewIntArray(supportedPrimitives.size());
-    env->SetIntArrayRegion(primitives, 0, supportedPrimitives.size(),
-                           reinterpret_cast<jint*>(supportedPrimitives.data()));
-    return primitives;
-}
-
-static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong effect,
-                                   jlong strength, jlong vibrationId) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorPerformEffect failed because native service was not initialized");
-        return -1;
-    }
-    aidl::Effect effectType = static_cast<aidl::Effect>(effect);
-    aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
-    auto callback = service->createCallback(vibrationId);
-    auto result = service->controller()->performEffect(effectType, effectStrength, callback);
-    return result.isOk() ? result.value().count() : -1;
-}
-
-static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
-                                          jobjectArray composition, jlong vibrationId) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorPerformComposedEffect failed because native service was not initialized");
-        return;
-    }
-    size_t size = env->GetArrayLength(composition);
-    std::vector<aidl::CompositeEffect> effects;
-    for (size_t i = 0; i < size; i++) {
-        jobject element = env->GetObjectArrayElement(composition, i);
-        effects.push_back(effectFromJavaPrimitive(env, element));
-    }
-    auto callback = service->createCallback(vibrationId);
-    service->controller()->performComposedEffect(effects, callback);
-}
-
-static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorGetCapabilities failed because native service was not initialized");
-        return 0;
-    }
-    auto result = service->controller()->getCapabilities();
-    return result.isOk() ? static_cast<jlong>(result.value()) : 0;
-}
-
-static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id,
-                                   jlong effect, jlong strength) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorAlwaysOnEnable failed because native service was not initialized");
-        return;
-    }
-    service->controller()->alwaysOnEnable(static_cast<int32_t>(id),
-                                          static_cast<aidl::Effect>(effect),
-                                          static_cast<aidl::EffectStrength>(strength));
-}
-
-static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id) {
-    NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
-    if (service == nullptr) {
-        ALOGE("vibratorAlwaysOnDisable failed because native service was not initialized");
-        return;
-    }
-    service->controller()->alwaysOnDisable(static_cast<int32_t>(id));
-}
-
-static const JNINativeMethod method_table[] = {
-        {"vibratorInit", "(Lcom/android/server/VibratorService$OnCompleteListener;)J",
-         (void*)vibratorInit},
-        {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
-        {"vibratorExists", "(J)Z", (void*)vibratorExists},
-        {"vibratorOn", "(JJJ)V", (void*)vibratorOn},
-        {"vibratorOff", "(J)V", (void*)vibratorOff},
-        {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
-        {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
-        {"vibratorPerformComposedEffect",
-         "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V",
-         (void*)vibratorPerformComposedEffect},
-        {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
-        {"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
-        {"vibratorSetExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
-        {"vibratorGetCapabilities", "(J)J", (void*)vibratorGetCapabilities},
-        {"vibratorAlwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
-        {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
-};
-
-int register_android_server_VibratorService(JavaVM* jvm, JNIEnv* env) {
-    sJvm = jvm;
-    jclass listenerClass =
-            FindClassOrDie(env, "com/android/server/VibratorService$OnCompleteListener");
-    sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(J)V");
-
-    jclass primitiveClass =
-            FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect");
-    sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
-    sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
-    sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
-
-    return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table,
-                                    NELEM(method_table));
-}
-
-}; // namespace android
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 5d78f12..c44cea3 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -122,7 +122,7 @@
         {
             std::unique_lock<std::mutex> reasonsLock(mReasonsMutex, std::defer_lock);
             if (reasonsLock.try_lock() && mWakeupReasons.empty()) {
-                mWakeupReasons = std::move(wakeupReasons);
+                mWakeupReasons = wakeupReasons;
                 reasonsCaptured = true;
             }
         }
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
new file mode 100644
index 0000000..afce537
--- /dev/null
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorController"
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <nativehelper/JNIHelp.h>
+#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include <vibratorservice/VibratorHalController.h>
+
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+namespace V1_2 = android::hardware::vibrator::V1_2;
+namespace V1_3 = android::hardware::vibrator::V1_3;
+namespace aidl = android::hardware::vibrator;
+
+namespace android {
+
+static JavaVM* sJvm = nullptr;
+static jmethodID sMethodIdOnComplete;
+static struct {
+    jfieldID id;
+    jfieldID scale;
+    jfieldID delay;
+} sPrimitiveClassInfo;
+
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
+              static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
+              static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
+              static_cast<uint8_t>(aidl::EffectStrength::STRONG));
+
+static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
+              static_cast<uint8_t>(aidl::Effect::CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
+              static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(aidl::Effect::TICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(aidl::Effect::THUD));
+static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(aidl::Effect::POP));
+static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
+              static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
+              static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
+              static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
+              static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
+              static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
+
+class VibratorControllerWrapper {
+public:
+    VibratorControllerWrapper(JNIEnv* env, int32_t vibratorId, jobject callbackListener)
+          // TODO(b/167946816): use ManagerHalController to get vibrator by id
+          : mHal(std::make_unique<vibrator::HalController>()),
+            mVibratorId(vibratorId),
+            mCallbackListener(env->NewGlobalRef(callbackListener)) {
+        LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
+                            "Unable to create global reference to vibration callback handler");
+    }
+
+    ~VibratorControllerWrapper() {
+        auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
+        jniEnv->DeleteGlobalRef(mCallbackListener);
+    }
+
+    vibrator::HalController* hal() const { return mHal.get(); }
+
+    std::function<void()> createCallback(jlong vibrationId) {
+        return [vibrationId, this]() {
+            auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
+            jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, mVibratorId,
+                                   vibrationId);
+        };
+    }
+
+private:
+    const std::unique_ptr<vibrator::HalController> mHal;
+    const int32_t mVibratorId;
+    const jobject mCallbackListener;
+};
+
+static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
+    aidl::CompositeEffect effect;
+    effect.primitive = static_cast<aidl::CompositePrimitive>(
+            env->GetIntField(primitive, sPrimitiveClassInfo.id));
+    effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale));
+    effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay));
+    return effect;
+}
+
+static void destroyNativeWrapper(void* ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper) {
+        delete wrapper;
+    }
+}
+
+static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jint vibratorId,
+                          jobject callbackListener) {
+    std::unique_ptr<VibratorControllerWrapper> wrapper =
+            std::make_unique<VibratorControllerWrapper>(env, vibratorId, callbackListener);
+    wrapper->hal()->init();
+    return reinterpret_cast<jlong>(wrapper.release());
+}
+
+static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeWrapper));
+}
+
+static jboolean vibratorIsAvailable(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorIsAvailable failed because native wrapper was not initialized");
+        return JNI_FALSE;
+    }
+    return wrapper->hal()->ping().isOk() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong timeoutMs,
+                       jlong vibrationId) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorOn failed because native wrapper was not initialized");
+        return;
+    }
+    auto callback = wrapper->createCallback(vibrationId);
+    wrapper->hal()->on(std::chrono::milliseconds(timeoutMs), callback);
+}
+
+static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorOff failed because native wrapper was not initialized");
+        return;
+    }
+    wrapper->hal()->off();
+}
+
+static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong ptr, jint amplitude) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorSetAmplitude failed because native wrapper was not initialized");
+        return;
+    }
+    wrapper->hal()->setAmplitude(static_cast<int32_t>(amplitude));
+}
+
+static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong ptr,
+                                       jboolean enabled) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorSetExternalControl failed because native wrapper was not initialized");
+        return;
+    }
+    wrapper->hal()->setExternalControl(enabled);
+}
+
+static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorGetSupportedEffects failed because native wrapper was not initialized");
+        return nullptr;
+    }
+    auto result = wrapper->hal()->getSupportedEffects();
+    if (!result.isOk()) {
+        return nullptr;
+    }
+    std::vector<aidl::Effect> supportedEffects = result.value();
+    jintArray effects = env->NewIntArray(supportedEffects.size());
+    env->SetIntArrayRegion(effects, 0, supportedEffects.size(),
+                           reinterpret_cast<jint*>(supportedEffects.data()));
+    return effects;
+}
+
+static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorGetSupportedPrimitives failed because native wrapper was not initialized");
+        return nullptr;
+    }
+    auto result = wrapper->hal()->getSupportedPrimitives();
+    if (!result.isOk()) {
+        return nullptr;
+    }
+    std::vector<aidl::CompositePrimitive> supportedPrimitives = result.value();
+    jintArray primitives = env->NewIntArray(supportedPrimitives.size());
+    env->SetIntArrayRegion(primitives, 0, supportedPrimitives.size(),
+                           reinterpret_cast<jint*>(supportedPrimitives.data()));
+    return primitives;
+}
+
+static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong effect,
+                                   jlong strength, jlong vibrationId) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorPerformEffect failed because native wrapper was not initialized");
+        return -1;
+    }
+    aidl::Effect effectType = static_cast<aidl::Effect>(effect);
+    aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
+    auto callback = wrapper->createCallback(vibrationId);
+    auto result = wrapper->hal()->performEffect(effectType, effectStrength, callback);
+    return result.isOk() ? result.value().count() : -1;
+}
+
+static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong ptr,
+                                          jobjectArray composition, jlong vibrationId) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorPerformComposedEffect failed because native wrapper was not initialized");
+        return;
+    }
+    size_t size = env->GetArrayLength(composition);
+    std::vector<aidl::CompositeEffect> effects;
+    for (size_t i = 0; i < size; i++) {
+        jobject element = env->GetObjectArrayElement(composition, i);
+        effects.push_back(effectFromJavaPrimitive(env, element));
+    }
+    auto callback = wrapper->createCallback(vibrationId);
+    wrapper->hal()->performComposedEffect(effects, callback);
+}
+
+static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorGetCapabilities failed because native wrapper was not initialized");
+        return 0;
+    }
+    auto result = wrapper->hal()->getCapabilities();
+    return result.isOk() ? static_cast<jlong>(result.value()) : 0;
+}
+
+static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id,
+                                   jlong effect, jlong strength) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorAlwaysOnEnable failed because native wrapper was not initialized");
+        return;
+    }
+    wrapper->hal()->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
+                                   static_cast<aidl::EffectStrength>(strength));
+}
+
+static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorAlwaysOnDisable failed because native wrapper was not initialized");
+        return;
+    }
+    wrapper->hal()->alwaysOnDisable(static_cast<int32_t>(id));
+}
+
+static const JNINativeMethod method_table[] = {
+        {"vibratorInit",
+         "(ILcom/android/server/vibrator/VibratorController$OnVibrationCompleteListener;)J",
+         (void*)vibratorInit},
+        {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
+        {"vibratorIsAvailable", "(J)Z", (void*)vibratorIsAvailable},
+        {"vibratorOn", "(JJJ)V", (void*)vibratorOn},
+        {"vibratorOff", "(J)V", (void*)vibratorOff},
+        {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
+        {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
+        {"vibratorPerformComposedEffect",
+         "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V",
+         (void*)vibratorPerformComposedEffect},
+        {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
+        {"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
+        {"vibratorSetExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
+        {"vibratorGetCapabilities", "(J)J", (void*)vibratorGetCapabilities},
+        {"vibratorAlwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
+        {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
+};
+
+int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) {
+    sJvm = jvm;
+    auto listenerClassName =
+            "com/android/server/vibrator/VibratorController$OnVibrationCompleteListener";
+    jclass listenerClass = FindClassOrDie(env, listenerClassName);
+    sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(IJ)V");
+
+    jclass primitiveClass =
+            FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect");
+    sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
+    sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
+    sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
+
+    return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorController",
+                                    method_table, NELEM(method_table));
+}
+
+}; // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 79b5fed..5a0d08a 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -37,8 +37,8 @@
 int register_android_server_UsbMidiDevice(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_vr_VrManagerService(JNIEnv* env);
+int register_android_server_vibrator_VibratorController(JavaVM* vm, JNIEnv* env);
 int register_android_server_VibratorManagerService(JNIEnv* env);
-int register_android_server_VibratorService(JavaVM* vm, 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);
@@ -90,8 +90,8 @@
     register_android_server_UsbAlsaJackDetector(env);
     register_android_server_UsbHostManager(env);
     register_android_server_vr_VrManagerService(env);
+    register_android_server_vibrator_VibratorController(vm, env);
     register_android_server_VibratorManagerService(env);
-    register_android_server_VibratorService(vm, env);
     register_android_server_SystemServer(env);
     register_android_server_location_GnssLocationProvider(env);
     register_android_server_connectivity_Vpn(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index d29534e..1a147b9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -98,6 +98,8 @@
     private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
     private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
     private static final String TAG_PASSWORD_QUALITY = "password-quality";
+    private static final String TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT =
+            "password-quality-applies-parent";
     private static final String TAG_POLICIES = "policies";
     private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS =
             "cross-profile-widget-providers";
@@ -143,6 +145,7 @@
 
     @NonNull
     PasswordPolicy mPasswordPolicy = new PasswordPolicy();
+    boolean mPasswordPolicyAppliesToParent = true;
 
     @DevicePolicyManager.PasswordComplexity
     int mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
@@ -333,6 +336,9 @@
                 writeAttributeValueToXml(
                         out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter);
             }
+
+            writeAttributeValueToXml(out, TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT,
+                    mPasswordPolicyAppliesToParent);
         }
         if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
             writeAttributeValueToXml(
@@ -626,6 +632,9 @@
             } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
                 mPasswordPolicy.nonLetter = Integer.parseInt(
                         parser.getAttributeValue(null, ATTR_VALUE));
+            } else if (TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT.equals(tag)) {
+                mPasswordPolicyAppliesToParent = Boolean.parseBoolean(
+                        parser.getAttributeValue(null, ATTR_VALUE));
             } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
                 maximumTimeToUnlock = Long.parseLong(
                         parser.getAttributeValue(null, ATTR_VALUE));
@@ -995,6 +1004,9 @@
         pw.print("minimumPasswordNonLetter=");
         pw.println(mPasswordPolicy.nonLetter);
 
+        pw.print("passwordPolicyAppliesToParent=");
+        pw.println(mPasswordPolicyAppliesToParent);
+
         pw.print("maximumTimeToUnlock=");
         pw.println(maximumTimeToUnlock);
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index ce61d50..05b1e425 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -101,4 +101,9 @@
     public boolean canProfileOwnerResetPasswordWhenLocked(int userId) {
         return false;
     }
+
+    public boolean hasKeyPair(String callerPackage, String alias) {
+        // STOPSHIP: implement delegation code in ArcDevicePolicyManagerWrapperService & nuke this.
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a646682..01b8c0b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -155,10 +155,12 @@
 import android.app.admin.SystemUpdatePolicy;
 import android.app.admin.UnsafeStateException;
 import android.app.backup.IBackupManager;
+import android.app.compat.CompatChanges;
 import android.app.trust.TrustManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -231,6 +233,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Telephony;
+import android.security.AppUriAuthenticationPolicy;
 import android.security.IKeyChainAliasCallback;
 import android.security.IKeyChainService;
 import android.security.KeyChain;
@@ -527,6 +530,19 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
     private static final long USE_SET_LOCATION_ENABLED = 117835097L;
 
+    /**
+     * Admin apps targeting Android S+ may not use
+     * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} to set password quality
+     * on the {@code DevicePolicyManager} instance obtained by calling
+     * {@link android.app.admin.DevicePolicyManager#getParentProfileInstance}.
+     * Instead, they should use
+     * {@link android.app.admin.DevicePolicyManager#setRequiredPasswordComplexity} to set
+     * coarse-grained password requirements device-wide.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+    private static final long PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT = 165573442L;
+
     final Context mContext;
     final Injector mInjector;
     final IPackageManager mIPackageManager;
@@ -972,29 +988,21 @@
     }
 
     /**
-     * Checks if the feature is supported and it's safe to execute the given {@code operation}.
-     *
-     * <p>Typically called at the beginning of each API method as:
-     *
-     * <pre><code>
-     *
-     * if (!canExecute(operation, permission)) return;
-     *
-     * </code></pre>
-     *
-     * @return {@code true} when it's safe to execute, {@code false} when the feature is not
-     * supported or the caller does not have the given {@code requiredPermission}.
+     * Checks if it's safe to execute the given {@code operation}.
      *
      * @throws UnsafeStateException if it's not safe to execute the operation.
      */
-    boolean canExecute(@DevicePolicyOperation int operation, @NonNull String requiredPermission) {
-        if (!mHasFeature && !hasCallingPermission(requiredPermission)) {
-            return false;
+    private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
+        if (!canExecute(operation)) {
+            throw mSafetyChecker.newUnsafeStateException(operation);
         }
-        if (mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation)) {
-            return true;
-        }
-        throw mSafetyChecker.newUnsafeStateException(operation);
+    }
+
+    /**
+     * Returns whether it's safe to execute the given {@code operation}.
+     */
+    boolean canExecute(@DevicePolicyOperation int operation) {
+        return mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation);
     }
 
     /**
@@ -1147,6 +1155,10 @@
             return LocalServices.getService(PersistentDataBlockManagerInternal.class);
         }
 
+        AppOpsManager getAppOpsManager() {
+            return mContext.getSystemService(AppOpsManager.class);
+        }
+
         LockSettingsInternal getLockSettingsInternal() {
             return LocalServices.getService(LockSettingsInternal.class);
         }
@@ -1396,6 +1408,10 @@
         public long systemCurrentTimeMillis() {
             return System.currentTimeMillis();
         }
+
+        public boolean isChangeEnabled(long changeId, String packageName, int userId) {
+            return CompatChanges.isChangeEnabled(changeId, packageName, UserHandle.of(userId));
+        }
     }
 
     /**
@@ -1576,33 +1592,15 @@
      * Creates a new {@link CallerIdentity} object to represent the caller's identity.
      */
     private CallerIdentity getCallerIdentity() {
-        final int callerUid = mInjector.binderGetCallingUid();
-        return new CallerIdentity(callerUid, null, null);
+        return getCallerIdentity(null, null);
     }
 
     /**
      * Creates a new {@link CallerIdentity} object to represent the caller's identity.
      */
-    private CallerIdentity getCallerIdentity(@NonNull String callerPackage) {
-        final int callerUid = mInjector.binderGetCallingUid();
+    private CallerIdentity getCallerIdentity(@Nullable String callerPackage) {
 
-        if (!isCallingFromPackage(callerPackage, callerUid)) {
-            throw new SecurityException(
-                    String.format("Caller with uid %d is not %s", callerUid, callerPackage));
-        }
-
-        return new CallerIdentity(callerUid, callerPackage, null);
-    }
-
-    /**
-     * Creates a new {@link CallerIdentity} object to represent the caller's identity.
-     */
-    @VisibleForTesting
-    protected CallerIdentity getCallerIdentity(@Nullable ComponentName adminComponent,
-            @NonNull String callerPackage) {
-        return adminComponent == null
-                ? getCallerIdentity(callerPackage)
-                : getCallerIdentity(adminComponent);
+        return getCallerIdentity(null, callerPackage);
     }
 
     /**
@@ -1610,138 +1608,49 @@
      * The component name should be an active admin for the calling user.
      */
     @VisibleForTesting
-    protected CallerIdentity getCallerIdentity(@NonNull ComponentName adminComponent) {
-        final int callerUid = mInjector.binderGetCallingUid();
-        final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid));
-        ActiveAdmin admin = policy.mAdminMap.get(adminComponent);
-
-        if (admin == null) {
-            throw new SecurityException(String.format("No active admin for %s", adminComponent));
-        }
-        if (admin.getUid() != callerUid) {
-            throw new SecurityException(
-                    String.format("Admin %s is not owned by uid %d", adminComponent, callerUid));
-        }
-
-        return new CallerIdentity(callerUid, adminComponent.getPackageName(), adminComponent);
-    }
-
-    /**
-     * Creates a new {@link CallerIdentity} object to represent the caller's identity, which should
-     * be an admin of a profile on the device. If no component name is provided, look up the
-     * component name and fill it in for the caller.
-     *
-     * Note: this method should only be called when the expected caller is an admin.
-     *
-     * @throws SecurityException if the caller is not an active admin.
-     */
-    private CallerIdentity getAdminCallerIdentity(@Nullable ComponentName adminComponent) {
-        if (adminComponent == null) {
-            ActiveAdmin admin = getActiveAdminOfCaller();
-            if (admin != null) {
-                return getCallerIdentity(admin.info.getComponent());
-            }
-            throw new SecurityException("Caller is not an active admin");
-        } else {
-            return getCallerIdentity(adminComponent);
-        }
-    }
-
-    /**
-     * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
-     * component name is provided, look up the component name and fill it in for the caller.
-     *
-     * Note: this method should only be called when the caller may not be an admin. If the caller
-     * is not an admin, the ComponentName in the returned identity will be null.
-     */
-    private CallerIdentity getNonPrivilegedOrAdminCallerIdentity(
-            @Nullable ComponentName adminComponent) {
-        if (adminComponent == null) {
-            ActiveAdmin admin = getActiveAdminOfCaller();
-            if (admin != null) {
-                adminComponent = admin.info.getComponent();
-            } else {
-                return getCallerIdentity();
-            }
-        }
-        return getCallerIdentity(adminComponent);
-
-    }
-
-    /**
-     * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
-     * package name is provided, look up the package name and fill it in for the caller.
-     *
-     * Note: this method should only be called when the expected caller is an admin.
-     *
-     * @throws SecurityException if the caller is not an active admin.
-     */
-    private CallerIdentity getAdminCallerIdentityUsingPackage(@Nullable String callerPackage) {
-        if (callerPackage == null) {
-            ActiveAdmin admin = getActiveAdminOfCaller();
-            if (admin != null) {
-                return getCallerIdentity(admin.info.getPackageName());
-            }
-            throw new SecurityException("Caller is not an active admin");
-        }
-        return getCallerIdentity(callerPackage);
-    }
-
-    /**
-     * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
-     * package name is provided, look up the package name and fill it in for the caller.
-     */
-    private CallerIdentity getNonPrivilegedOrAdminCallerIdentityUsingPackage(
-            @Nullable String callerPackage) {
-        if (callerPackage == null) {
-            ActiveAdmin admin = getActiveAdminOfCaller();
-            if (admin != null) {
-                callerPackage = admin.info.getPackageName();
-            } else {
-                return getCallerIdentity();
-            }
-        }
-        return getCallerIdentity(callerPackage);
+    CallerIdentity getCallerIdentity(@Nullable ComponentName adminComponent) {
+        return getCallerIdentity(adminComponent, null);
     }
 
     /**
      * Creates a new {@link CallerIdentity} object to represent the caller's identity.
-     * If an {@code adminComponent} is specified, then the caller must be an admin and
-     * the provided component name must match the caller's UID.
-     *
-     * If a package name is provided, then the caller doesn't have to be an admin, and the
-     * provided package must belong to the caller's UID.
-     *
-     * If neither is provided, the caller identity is returned as-is.
-     *
-     * Note: this method should only be called when the caller may not be an admin. If the caller
-     * is not an admin, the ComponentName in the returned identity will be null.
+     * If {@code adminComponent} is provided, it's validated against the list of known
+     * active admins and caller uid. If {@code callerPackage} is provided, it's validated
+     * against the caller uid. If a valid {@code adminComponent} is provided but not
+     * {@code callerPackage}, the package name of the {@code adminComponent} is used instead.
      */
-    private CallerIdentity getNonPrivilegedOrAdminCallerIdentity(
-            @Nullable ComponentName adminComponent,
+    @VisibleForTesting
+    CallerIdentity getCallerIdentity(@Nullable ComponentName adminComponent,
             @Nullable String callerPackage) {
-        if (adminComponent != null) {
-            return getCallerIdentity(adminComponent);
-        }
-
-        return getNonPrivilegedOrAdminCallerIdentityUsingPackage(callerPackage);
-    }
-
-    /**
-     * Retrieves the active admin of the caller. This method should not be called directly and
-     * should only be called by {@link #getAdminCallerIdentity},
-     * {@link #getNonPrivilegedOrAdminCallerIdentity}, {@link #getAdminCallerIdentityUsingPackage}
-     * or {@link #getNonPrivilegedOrAdminCallerIdentityUsingPackage}.
-     */
-    private ActiveAdmin getActiveAdminOfCaller() {
         final int callerUid = mInjector.binderGetCallingUid();
-        final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid));
-        for (ActiveAdmin admin : policy.mAdminList) {
-            if (admin.getUid() == callerUid) {
-                return admin;
+
+        if (callerPackage != null) {
+            if (!isCallingFromPackage(callerPackage, callerUid)) {
+                throw new SecurityException(
+                        String.format("Caller with uid %d is not %s", callerUid, callerPackage));
             }
         }
-        return null;
+
+        if (adminComponent != null) {
+            final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid));
+            ActiveAdmin admin = policy.mAdminMap.get(adminComponent);
+
+            if (admin == null) {
+                throw new SecurityException(String.format(
+                        "No active admin for %s", adminComponent));
+            }
+            if (admin.getUid() != callerUid) {
+                throw new SecurityException(String.format(
+                        "Admin %s is not owned by uid %d", adminComponent, callerUid));
+            }
+            if (callerPackage != null) {
+                Preconditions.checkArgument(callerPackage.equals(adminComponent.getPackageName()));
+            } else {
+                callerPackage = adminComponent.getPackageName();
+            }
+        }
+
+        return new CallerIdentity(callerUid, callerPackage, adminComponent);
     }
 
     /**
@@ -3192,6 +3101,11 @@
         }
     }
 
+    private void checkAllUsersAreAffiliatedWithDevice() {
+        Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked(),
+                "operation not allowed when device has unaffiliated users");
+    }
+
     @Override
     public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
         if (!mHasFeature) {
@@ -3417,6 +3331,11 @@
                 getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
     }
 
+    private boolean canSetPasswordQualityOnParent(String packageName, int userId) {
+        return !mInjector.isChangeEnabled(
+                PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT, packageName, userId);
+    }
+
     @Override
     public void setPasswordQuality(ComponentName who, int quality, boolean parent) {
         if (!mHasFeature) {
@@ -3425,7 +3344,18 @@
         Objects.requireNonNull(who, "ComponentName is null");
         validateQualityConstant(quality);
 
-        final int userId = mInjector.userHandleGetCallingUserId();
+        final CallerIdentity caller = getCallerIdentity(who);
+        Preconditions.checkCallAuthorization(
+                isProfileOwner(caller) || isDeviceOwner(caller) || isSystemUid(caller));
+
+        final boolean qualityMayApplyToParent =
+                canSetPasswordQualityOnParent(who.getPackageName(), caller.getUserId());
+        if (!qualityMayApplyToParent) {
+            Preconditions.checkArgument(!parent,
+                    "Profile Owner may not apply password quality requirements device-wide");
+        }
+
+        final int userId = caller.getUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
@@ -3434,6 +3364,7 @@
                 if (passwordPolicy.quality != quality) {
                     passwordPolicy.quality = quality;
                     ap.mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
+                    ap.mPasswordPolicyAppliesToParent = qualityMayApplyToParent;
                     resetInactivePasswordRequirementsIfRPlus(userId, ap);
                     updatePasswordValidityCheckpointLocked(userId, parent);
                     updatePasswordQualityCacheForUserGroup(userId);
@@ -4165,7 +4096,16 @@
         synchronized (getLockObject()) {
             List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userId);
             for (ActiveAdmin admin : admins) {
-                adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
+                final boolean isAdminOfUser = userId == admin.getUserHandle().getIdentifier();
+                // Use the password metrics from the admin in one of three cases:
+                // (1) The admin is of the user we're getting the minimum metrics for. The admin
+                //     always affects the user it's managing. This applies also to the parent
+                //     ActiveAdmin instance: It'd have the same user handle.
+                // (2) The mPasswordPolicyAppliesToParent field is true: That indicates the
+                //     call to setPasswordQuality was made by an admin that may affect the parent.
+                if (isAdminOfUser || admin.mPasswordPolicyAppliesToParent) {
+                    adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
+                }
             }
         }
         return PasswordMetrics.merge(adminMetrics);
@@ -4257,13 +4197,13 @@
                     /* shouldIncludeProfileAdmins */ (user) -> user.id == profileUser
                     || !mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id));
             ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>(admins.size());
+            int maxRequiredComplexity = PASSWORD_COMPLEXITY_NONE;
             for (ActiveAdmin admin : admins) {
                 adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
+                maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
             }
-            //TODO: Take complexity into account, would need to take complexity from all admins
-            //in the admins list.
             return PasswordMetrics.validatePasswordMetrics(PasswordMetrics.merge(adminMetrics),
-                    PASSWORD_COMPLEXITY_NONE, false, metrics).isEmpty();
+                    maxRequiredComplexity, false, metrics).isEmpty();
         }
     }
 
@@ -4307,7 +4247,7 @@
     @Override
     @PasswordComplexity
     public int getPasswordComplexity(boolean parent) {
-        final CallerIdentity caller = getNonPrivilegedOrAdminCallerIdentity(null);
+        final CallerIdentity caller = getCallerIdentity();
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.GET_USER_PASSWORD_COMPLEXITY_LEVEL)
                 .setStrings(parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT,
@@ -4315,15 +4255,18 @@
                                 mInjector.binderGetCallingUid()))
                 .write();
 
-        Preconditions.checkCallAuthorization(!parent || (isDeviceOwner(caller)
-                        || isProfileOwner(caller) || isSystemUid(caller)),
-                "Only profile owner, device owner and system may call this method.");
         enforceUserUnlocked(caller.getUserId());
-        Preconditions.checkCallAuthorization(
-                hasCallingOrSelfPermission(REQUEST_PASSWORD_COMPLEXITY)
-                        || isDeviceOwner(caller) || isProfileOwner(caller),
-                "Must have " + REQUEST_PASSWORD_COMPLEXITY
-                        + " permission, or be a profile owner or device owner.");
+        if (parent) {
+            Preconditions.checkCallAuthorization(
+                    isDeviceOwner(caller) || isProfileOwner(caller) || isSystemUid(caller),
+                    "Only profile owner, device owner and system may call this method on parent.");
+        } else {
+            Preconditions.checkCallAuthorization(
+                    hasCallingOrSelfPermission(REQUEST_PASSWORD_COMPLEXITY)
+                            || isDeviceOwner(caller) || isProfileOwner(caller),
+                    "Must have " + REQUEST_PASSWORD_COMPLEXITY
+                            + " permission, or be a profile owner or device owner.");
+        }
 
         synchronized (getLockObject()) {
             final int credentialOwner = getCredentialOwner(caller.getUserId(), parent);
@@ -4342,7 +4285,7 @@
         Preconditions.checkArgument(allowedModes.contains(passwordComplexity),
                 "Provided complexity is not one of the allowed values.");
 
-        final CallerIdentity caller = getAdminCallerIdentity(null);
+        final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
         Preconditions.checkArgument(!calledOnParent || isProfileOwner(caller));
 
@@ -4354,28 +4297,33 @@
                     admin.mPasswordComplexity = passwordComplexity;
                     // Reset the password policy.
                     admin.mPasswordPolicy = new PasswordPolicy();
+                    admin.mPasswordPolicyAppliesToParent = true;
                     updatePasswordValidityCheckpointLocked(caller.getUserId(), calledOnParent);
                     updatePasswordQualityCacheForUserGroup(caller.getUserId());
                     saveSettingsLocked(caller.getUserId());
-                    //TODO: Log password complexity change if security logging is enabled.
                 });
             }
+            logPasswordComplexityRequiredIfSecurityLogEnabled(admin.info.getComponent(),
+                    caller.getUserId(), calledOnParent, passwordComplexity);
         }
         //TODO: Log metrics.
     }
 
+    private void logPasswordComplexityRequiredIfSecurityLogEnabled(ComponentName who, int userId,
+            boolean parent, int complexity) {
+        if (SecurityLog.isLoggingEnabled()) {
+            final int affectedUserId = parent ? getProfileParentId(userId) : userId;
+            SecurityLog.writeEvent(SecurityLog.TAG_PASSWORD_COMPLEXITY_REQUIRED,
+                    who.getPackageName(), userId, affectedUserId, complexity);
+        }
+    }
+
     private int getEffectivePasswordComplexityRequirementLocked(@UserIdInt int userHandle) {
         ensureLocked();
         List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle);
         int maxRequiredComplexity = PASSWORD_COMPLEXITY_NONE;
         for (ActiveAdmin admin : admins) {
-            final ComponentName adminComponent = admin.info.getComponent();
-            final int adminUser = admin.getUserHandle().getIdentifier();
-            // Password complexity is only taken into account from DO/PO
-            if (isDeviceOwner(adminComponent, adminUser)
-                    || isProfileOwnerUncheckedLocked(adminComponent, adminUser)) {
-                maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
-            }
+            maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
         }
         return maxRequiredComplexity;
     }
@@ -4386,11 +4334,11 @@
             return PASSWORD_COMPLEXITY_NONE;
         }
 
-        final CallerIdentity caller = getAdminCallerIdentity(null);
+        final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(
                 isDeviceOwner(caller) || isProfileOwner(caller));
 
-        Preconditions.checkArgument(!calledOnParent || hasProfileOwner(caller.getUserId()));
+        Preconditions.checkArgument(!calledOnParent || isProfileOwner(caller));
 
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getParentOfAdminIfRequired(
@@ -4400,6 +4348,21 @@
     }
 
     @Override
+    public int getAggregatedPasswordComplexityForUser(int userId) {
+        if (!mHasFeature) {
+            return PASSWORD_COMPLEXITY_NONE;
+        }
+
+        final CallerIdentity caller = getCallerIdentity();
+        Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
+
+        synchronized (getLockObject()) {
+            return getEffectivePasswordComplexityRequirementLocked(userId);
+        }
+    }
+
+
+    @Override
     public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
         if (!mLockPatternUtils.hasSecureLockScreen()) {
             return 0;
@@ -4879,10 +4842,6 @@
 
     @Override
     public void lockNow(int flags, boolean parent) {
-        if (!canExecute(DevicePolicyManager.OPERATION_LOCK_NOW, permission.LOCK_DEVICE)) {
-            return;
-        }
-
         final CallerIdentity caller = getCallerIdentity();
 
         final int callingUserId = caller.getUserId();
@@ -4895,6 +4854,7 @@
                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
                     parent,
                     android.Manifest.permission.LOCK_DEVICE);
+            checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOCK_NOW);
             final long ident = mInjector.binderClearCallingIdentity();
             try {
                 adminComponent = admin == null ? null : admin.info.getComponent();
@@ -5076,7 +5036,8 @@
         final CallerIdentity caller = getCallerIdentity(who, callerPackage);
         Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                 && (isProfileOwner(caller) || isDeviceOwner(caller)))
-                || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+                || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+                || isCredentialManagementApp(caller, alias, isUserSelectable))));
 
         final long id = mInjector.binderClearCallingIdentity();
         try {
@@ -5116,7 +5077,8 @@
         final CallerIdentity caller = getCallerIdentity(who, callerPackage);
         Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                 && (isProfileOwner(caller) || isDeviceOwner(caller)))
-                || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+                || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+                || isCredentialManagementApp(caller, alias))));
 
         final long id = Binder.clearCallingIdentity();
         try {
@@ -5145,6 +5107,30 @@
     }
 
     @Override
+    public boolean hasKeyPair(String callerPackage, String alias) {
+        final CallerIdentity caller = getCallerIdentity(callerPackage);
+        Preconditions.checkCallAuthorization(canManageCertificates(caller));
+
+        return mInjector.binderWithCleanCallingIdentity(() -> {
+            try (KeyChainConnection keyChainConnection =
+                         KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
+                return keyChainConnection.getService().containsKeyPair(alias);
+            } catch (RemoteException e) {
+                Log.e(LOG_TAG, "Querying keypair", e);
+            } catch (InterruptedException e) {
+                Log.w(LOG_TAG, "Interrupted while querying keypair", e);
+                Thread.currentThread().interrupt();
+            }
+            return false;
+        });
+    }
+
+    private boolean canManageCertificates(CallerIdentity caller) {
+        return isProfileOwner(caller) || isDeviceOwner(caller)
+                || isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
+    }
+
+    @Override
     public boolean setKeyGrantForApp(ComponentName who, String callerPackage, String alias,
             String packageName, boolean hasGrant) {
         Preconditions.checkStringNotEmpty(alias, "Alias to grant cannot be empty");
@@ -5222,9 +5208,7 @@
          */
         if (hasProfileOwner(caller.getUserId())) {
             // Make sure that the caller is the profile owner or delegate.
-            Preconditions.checkCallAuthorization(
-                    isDeviceOwner(caller) || isProfileOwner(caller) || isCallerDelegate(
-                            caller, DELEGATION_CERT_INSTALL));
+            Preconditions.checkCallAuthorization(canManageCertificates(caller));
             // Verify that the managed profile is on an organization-owned device and as such
             // the profile owner can access Device IDs.
             if (isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())) {
@@ -5298,7 +5282,8 @@
         } else {
             Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                     && (isProfileOwner(caller) || isDeviceOwner(caller)))
-                    || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+                    || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+                    || isCredentialManagementApp(caller, alias))));
         }
 
         // As the caller will be granted access to the key, ensure no UID was specified, as
@@ -5394,7 +5379,8 @@
         final CallerIdentity caller = getCallerIdentity(who, callerPackage);
         Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                 && (isProfileOwner(caller) || isDeviceOwner(caller)))
-                || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+                || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+                || isCredentialManagementApp(caller, alias))));
 
         final long id = mInjector.binderClearCallingIdentity();
         try (final KeyChainConnection keyChainConnection =
@@ -5626,15 +5612,18 @@
     public List<String> getDelegatedScopes(ComponentName who,
             String delegatePackage) throws SecurityException {
         Objects.requireNonNull(delegatePackage, "Delegate package is null");
-        final CallerIdentity caller = getNonPrivilegedOrAdminCallerIdentity(who, delegatePackage);
+        final CallerIdentity caller = getCallerIdentity(who);
 
         // Ensure the caller may call this method:
-        // * Either it's an admin
-        // * Or it's an app identified by its calling package name (the
-        // getNonPrivilegedOrAdminCallerIdentity method validated the UID and package match).
-        Preconditions.checkCallAuthorization(
-                (caller.hasAdminComponent() && (isProfileOwner(caller) || isDeviceOwner(caller)))
-                || delegatePackage != null);
+        // * Either it's a profile owner / device owner, if componentName is provided
+        // * Or it's an app querying its own delegation scopes
+        if (caller.hasAdminComponent()) {
+            Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        } else {
+            Preconditions.checkCallAuthorization(isPackage(caller, delegatePackage),
+                    String.format("Caller with uid %d is not %s", caller.getUid(),
+                            delegatePackage));
+        }
         synchronized (getLockObject()) {
             final DevicePolicyData policy = getUserData(caller.getUserId());
             // Retrieve the scopes assigned to delegatePackage, or null if no scope was given.
@@ -5826,6 +5815,70 @@
         }
     }
 
+    /**
+     * Check whether a caller application is the credential management app, which can access
+     * privileged APIs.
+     * <p>
+     * This is done by checking that the calling package is authorized to perform the app operation
+     * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}. The alias provided must be contained
+     * in the aliases specified in the credential management app's authentication policy. The
+     * key pair to install must not be user selectable.
+     *
+     * @param caller the calling identity
+     * @return {@code true} if the calling process is the credential management app.
+     */
+    private boolean isCredentialManagementApp(CallerIdentity caller, String alias,
+            boolean isUserSelectable) {
+        // Should not be user selectable
+        if (isUserSelectable) {
+            Log.e(LOG_TAG, "The credential management app is not allowed to install a "
+                    + "user selectable key pair");
+            return false;
+        }
+        return isCredentialManagementApp(caller, alias);
+    }
+
+    /**
+     * Check whether a caller application is the credential mangement app, which can access
+     * privileged APIs.
+     * <p>
+     * This is done by checking that the calling package is authorized to perform the app operation
+     * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}. The alias provided must be contained
+     * in the aliases specified in the credential management app's authentication policy.
+     *
+     * @param caller the calling identity
+     * @return {@code true} if the calling process is the credential management app.
+     */
+    private boolean isCredentialManagementApp(CallerIdentity caller, String alias) {
+        // Should include alias in authentication policy
+        try (KeyChainConnection connection = KeyChain.bindAsUser(mContext,
+                caller.getUserHandle())) {
+            if (!containsAlias(connection.getService().getCredentialManagementAppPolicy(), alias)) {
+                return false;
+            }
+        } catch (RemoteException | InterruptedException e) {
+            return false;
+        }
+
+        AppOpsManager appOpsManager = mInjector.getAppOpsManager();
+        return appOpsManager != null
+                ? appOpsManager.noteOpNoThrow(AppOpsManager.OP_MANAGE_CREDENTIALS, caller.getUid(),
+                caller.getPackageName(), null, null) == AppOpsManager.MODE_ALLOWED
+                : false;
+    }
+
+    private static boolean containsAlias(AppUriAuthenticationPolicy policy, String alias) {
+        for (Map.Entry<String, Map<Uri, String>> appsToUris :
+                policy.getAppAndUriMappings().entrySet()) {
+            for (Map.Entry<Uri, String> urisToAliases : appsToUris.getValue().entrySet()) {
+                if (urisToAliases.getValue().equals(alias)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public void setCertInstallerPackage(ComponentName who, String installerPackage)
             throws SecurityException {
@@ -5924,12 +5977,16 @@
 
     @Override
     public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
-        Objects.requireNonNull(admin, "ComponentName is null");
-
-        final CallerIdentity caller = getNonPrivilegedOrAdminCallerIdentity(admin);
-        Preconditions.checkCallAuthorization((caller.hasAdminComponent()
-                && (isDeviceOwner(caller) || isProfileOwner(caller)))
-                || hasCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK));
+        final CallerIdentity caller;
+        if (hasCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)) {
+            // TODO: CaptivePortalLoginActivity erroneously calls this method with a non-admin
+            // ComponentName, so we have to use a separate code path for it:
+            // getCallerIdentity(admin) will throw if the admin is not in the known admin list.
+            caller = getCallerIdentity();
+        } else {
+            caller = getCallerIdentity(admin);
+            Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+        }
 
         return mInjector.binderWithCleanCallingIdentity(
                 () -> mInjector.getConnectivityManager().isVpnLockdownEnabled(caller.getUserId()));
@@ -6209,6 +6266,10 @@
         return getFrpManagementAgentUid() != -1;
     }
 
+    /**
+     * Called by a privileged caller holding {@code BIND_DEVICE_ADMIN} permission to retrieve
+     * the remove warning for the given device admin.
+     */
     @Override
     public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
         if (!mHasFeature) {
@@ -6649,13 +6710,13 @@
      * active admins.
      */
     @Override
-    public boolean getStorageEncryption(ComponentName who, int userHandle) {
+    public boolean getStorageEncryption(@Nullable ComponentName who, int userHandle) {
         if (!mHasFeature) {
             return false;
         }
         Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
 
-        final CallerIdentity caller = getAdminCallerIdentity(who);
+        final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
 
         synchronized (getLockObject()) {
@@ -6689,12 +6750,9 @@
         }
         Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
 
-        final CallerIdentity caller = getAdminCallerIdentityUsingPackage(callerPackage);
+        final CallerIdentity caller = getCallerIdentity(callerPackage);
         Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
 
-        // It's not critical here, but let's make sure the package name is correct, in case
-        // we start using it for different purposes.
-        ensureCallerPackage(callerPackage);
 
         final ApplicationInfo ai;
         try {
@@ -7034,7 +7092,7 @@
         // next boot? Might not be needed given that this still requires user consent.
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
-        Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked());
+        checkAllUsersAreAffiliatedWithDevice();
 
         if (mBugreportCollectionManager.requestBugreport()) {
             DevicePolicyEventLogger
@@ -7430,6 +7488,12 @@
                     admin.getPackageName(), userId, "set-device-owner");
 
             Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
+
+            if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+                Slog.i(LOG_TAG, "manageUser: " + admin + " on user " + userId);
+
+                manageUser(admin, admin, caller.getUserId(), null);
+            }
             return true;
         }
     }
@@ -7571,6 +7635,10 @@
         return isProfileOwner(caller) && caller.getUserHandle().isSystem();
     }
 
+    private boolean isPackage(CallerIdentity caller, String packageName) {
+        return isCallingFromPackage(packageName, caller.getUid());
+    }
+
     @Override
     public ComponentName getDeviceOwnerComponent(boolean callingUserOnly) {
         if (!mHasFeature) {
@@ -8521,8 +8589,7 @@
         return true;
     }
 
-    private void enforceCanCallLockTaskLocked(ComponentName who) {
-        final CallerIdentity caller = getAdminCallerIdentity(who);
+    private void enforceCanCallLockTaskLocked(CallerIdentity caller) {
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
 
         final int userId =  caller.getUserId();
@@ -8531,22 +8598,6 @@
         }
     }
 
-    private void ensureCallerPackage(@Nullable String packageName) {
-        if (packageName == null) {
-            enforceSystemCaller("omit package name");
-        } else {
-            final int callingUid = mInjector.binderGetCallingUid();
-            final int userId = mInjector.userHandleGetCallingUserId();
-            try {
-                final ApplicationInfo ai = mIPackageManager.getApplicationInfo(
-                        packageName, 0, userId);
-                Preconditions.checkState(ai.uid == callingUid, "Unmatching package name");
-            } catch (RemoteException e) {
-                // Shouldn't happen
-            }
-        }
-    }
-
     private boolean isCallerWithSystemUid() {
         return UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID);
     }
@@ -8643,6 +8694,7 @@
             pw.println(policy.mUserControlDisabledPackages);
             pw.print("mAppsSuspended="); pw.println(policy.mAppsSuspended);
             pw.print("mUserSetupComplete="); pw.println(policy.mUserSetupComplete);
+            pw.print("mAffiliationIds="); pw.println(policy.mAffiliationIds);
             pw.decreaseIndent();
         }
     }
@@ -8842,7 +8894,7 @@
         Objects.requireNonNull(agent, "agent null");
         Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
 
-        final CallerIdentity caller = getAdminCallerIdentity(admin);
+        final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
 
         synchronized (getLockObject()) {
@@ -9414,6 +9466,8 @@
         Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
                 "createAndManageUser was called from non-system user");
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
+
         final boolean ephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
         final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
                 && UserManager.isDeviceInDemoMode(mContext);
@@ -9493,29 +9547,7 @@
 
         final long id = mInjector.binderClearCallingIdentity();
         try {
-            final String adminPkg = admin.getPackageName();
-            try {
-                // Install the profile owner if not present.
-                if (!mIPackageManager.isPackageAvailable(adminPkg, userHandle)) {
-                    mIPackageManager.installExistingPackageAsUser(adminPkg, userHandle,
-                            PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
-                            PackageManager.INSTALL_REASON_POLICY, null);
-                }
-            } catch (RemoteException e) {
-                // Does not happen, same process
-            }
-
-            // Set admin.
-            setActiveAdmin(profileOwner, true, userHandle);
-            final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
-            setProfileOwner(profileOwner, ownerName, userHandle);
-
-            synchronized (getLockObject()) {
-                DevicePolicyData policyData = getUserData(userHandle);
-                policyData.mInitBundle = adminExtras;
-                policyData.mAdminBroadcastPending = true;
-                saveSettingsLocked(userHandle);
-            }
+            manageUser(admin, profileOwner, userHandle, adminExtras);
 
             if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -9536,12 +9568,53 @@
         }
     }
 
+    private void manageUser(ComponentName admin, ComponentName profileOwner,
+            @UserIdInt int userId, PersistableBundle adminExtras) {
+        // Check for permission
+        final CallerIdentity caller = getCallerIdentity();
+        Preconditions.checkCallAuthorization(canManageUsers(caller));
+        Preconditions.checkCallAuthorization(
+                hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+        mInjector.binderWithCleanCallingIdentity(() ->
+                    manageUserNoCheck(admin, profileOwner, userId, adminExtras));
+    }
+
+    private void manageUserNoCheck(ComponentName admin, ComponentName profileOwner,
+            int user, PersistableBundle adminExtras) {
+
+        final String adminPkg = admin.getPackageName();
+        try {
+            // Install the profile owner if not present.
+            if (!mIPackageManager.isPackageAvailable(adminPkg, user)) {
+                mIPackageManager.installExistingPackageAsUser(adminPkg, user,
+                        PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+                        PackageManager.INSTALL_REASON_POLICY, null);
+            }
+        } catch (RemoteException e) {
+            // Does not happen, same process
+        }
+
+        // Set admin.
+        setActiveAdmin(profileOwner, true, user);
+        final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
+        setProfileOwner(profileOwner, ownerName, user);
+
+        synchronized (getLockObject()) {
+            DevicePolicyData policyData = getUserData(user);
+            policyData.mInitBundle = adminExtras;
+            policyData.mAdminBroadcastPending = true;
+
+            saveSettingsLocked(user);
+        }
+    }
+
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
         Objects.requireNonNull(who, "ComponentName is null");
         Objects.requireNonNull(userHandle, "UserHandle is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_REMOVE_USER);
 
         return mInjector.binderWithCleanCallingIdentity(() -> {
             String restriction = isManagedProfile(userHandle.getIdentifier())
@@ -9575,6 +9648,7 @@
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SWITCH_USER);
 
         synchronized (getLockObject()) {
             long id = mInjector.binderClearCallingIdentity();
@@ -9599,6 +9673,7 @@
         Objects.requireNonNull(userHandle, "UserHandle is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_START_USER_IN_BACKGROUND);
 
         final int userId = userHandle.getIdentifier();
         if (isManagedProfile(userId)) {
@@ -9632,6 +9707,7 @@
         Objects.requireNonNull(userHandle, "UserHandle is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_STOP_USER);
 
         final int userId = userHandle.getIdentifier();
         if (isManagedProfile(userId)) {
@@ -10551,10 +10627,11 @@
             throws SecurityException {
         Objects.requireNonNull(who, "ComponentName is null");
         Objects.requireNonNull(packages, "packages is null");
+        final CallerIdentity caller = getCallerIdentity(who);
 
         synchronized (getLockObject()) {
-            enforceCanCallLockTaskLocked(who);
-            final int userHandle = mInjector.userHandleGetCallingUserId();
+            enforceCanCallLockTaskLocked(caller);
+            final int userHandle = caller.getUserId();
             setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
         }
     }
@@ -10571,10 +10648,11 @@
     @Override
     public String[] getLockTaskPackages(ComponentName who) {
         Objects.requireNonNull(who, "ComponentName is null");
+        final CallerIdentity caller = getCallerIdentity(who);
+        final int userHandle = caller.getUserId();
 
-        final int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
         synchronized (getLockObject()) {
-            enforceCanCallLockTaskLocked(who);
+            enforceCanCallLockTaskLocked(caller);
             final List<String> packages = getUserData(userHandle).mLockTaskPackages;
             return packages.toArray(new String[packages.size()]);
         }
@@ -10601,9 +10679,10 @@
         Preconditions.checkArgument(hasHome || !hasNotification,
             "Cannot use LOCK_TASK_FEATURE_NOTIFICATIONS without LOCK_TASK_FEATURE_HOME");
 
-        final int userHandle = mInjector.userHandleGetCallingUserId();
+        final CallerIdentity caller = getCallerIdentity(who);
+        final int userHandle = caller.getUserId();
         synchronized (getLockObject()) {
-            enforceCanCallLockTaskLocked(who);
+            enforceCanCallLockTaskLocked(caller);
             setLockTaskFeaturesLocked(userHandle, flags);
         }
     }
@@ -10618,9 +10697,10 @@
     @Override
     public int getLockTaskFeatures(ComponentName who) {
         Objects.requireNonNull(who, "ComponentName is null");
-        final int userHandle = mInjector.userHandleGetCallingUserId();
+        final CallerIdentity caller = getCallerIdentity(who);
+        final int userHandle = caller.getUserId();
         synchronized (getLockObject()) {
-            enforceCanCallLockTaskLocked(who);
+            enforceCanCallLockTaskLocked(caller);
             return getUserData(userHandle).mLockTaskFeatures;
         }
     }
@@ -11069,7 +11149,7 @@
 
     @Override
     public boolean setStatusBarDisabled(ComponentName who, boolean disabled) {
-        final CallerIdentity caller = getAdminCallerIdentity(who);
+        final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
 
         int userId = caller.getUserId();
@@ -11623,6 +11703,27 @@
         public ComponentName getProfileOwnerAsUser(int userHandle) {
             return DevicePolicyManagerService.this.getProfileOwnerAsUser(userHandle);
         }
+
+        @Override
+        public boolean isDeviceOrProfileOwnerInCallingUser(String packageName) {
+            return isDeviceOwnerInCallingUser(packageName)
+                    || isProfileOwnerInCallingUser(packageName);
+        }
+
+        private boolean isDeviceOwnerInCallingUser(String packageName) {
+            final ComponentName deviceOwnerInCallingUser =
+                    DevicePolicyManagerService.this.getDeviceOwnerComponent(
+                            /* callingUserOnly= */ true);
+            return deviceOwnerInCallingUser != null
+                    && packageName.equals(deviceOwnerInCallingUser.getPackageName());
+        }
+
+        private boolean isProfileOwnerInCallingUser(String packageName) {
+            final ComponentName profileOwnerInCallingUser =
+                    getProfileOwnerAsUser(UserHandle.getCallingUserId());
+            return profileOwnerInCallingUser != null
+                    && packageName.equals(profileOwnerInCallingUser.getPackageName());
+        }
     }
 
     private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
@@ -12184,8 +12285,6 @@
                 if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
                     return CODE_USER_SETUP_COMPLETED;
                 }
-            }  else {
-                // STOPSHIP Do proper check in split user mode
             }
             return CODE_OK;
         }
@@ -12832,7 +12931,7 @@
         }
 
         final Set<String> affiliationIds = new ArraySet<>(ids);
-        final CallerIdentity caller = getAdminCallerIdentity(admin);
+        final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
         final int callingUserId = caller.getUserId();
 
@@ -12925,13 +13024,6 @@
         });
     }
 
-    private boolean canStartSecurityLogging() {
-        synchronized (getLockObject()) {
-            return isOrganizationOwnedDeviceWithManagedProfile()
-                    || areAllUsersAffiliatedWithDeviceLocked();
-        }
-    }
-
     private @UserIdInt int getSecurityLoggingEnabledUser() {
         synchronized (getLockObject()) {
             if (mOwners.hasDeviceOwner()) {
@@ -13651,7 +13743,7 @@
         final CallerIdentity caller = getCallerIdentity(admin, packageName);
         Preconditions.checkCallAuthorization((caller.hasAdminComponent() &&  isDeviceOwner(caller))
                 || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING)));
-        Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked());
+        checkAllUsersAreAffiliatedWithDevice();
 
         synchronized (getLockObject()) {
             if (mNetworkLogger == null || !isNetworkLoggingEnabledInternalLocked()) {
@@ -13787,7 +13879,7 @@
         if (token == null || token.length < 32) {
             throw new IllegalArgumentException("token must be at least 32-byte long");
         }
-        final CallerIdentity caller = getAdminCallerIdentity(admin);
+        final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
 
         synchronized (getLockObject()) {
@@ -13811,7 +13903,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return false;
         }
-        final CallerIdentity caller = getAdminCallerIdentity(admin);
+        final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
 
         synchronized (getLockObject()) {
@@ -13836,7 +13928,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return false;
         }
-        final CallerIdentity caller = getAdminCallerIdentity(admin);
+        final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
 
         synchronized (getLockObject()) {
@@ -13861,7 +13953,7 @@
         }
         Objects.requireNonNull(token);
 
-        final CallerIdentity caller = getAdminCallerIdentity(admin);
+        final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
 
         synchronized (getLockObject()) {
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 7c3b7a6..49a41f0 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -74,7 +74,14 @@
 
     @Override
     public void onStart() {
-        publishBinderService(Context.PEOPLE_SERVICE, mService);
+        onStart(/* isForTesting= */ false);
+    }
+
+    @VisibleForTesting
+    protected void onStart(boolean isForTesting) {
+        if (!isForTesting) {
+            publishBinderService(Context.PEOPLE_SERVICE, mService);
+        }
         publishLocalService(PeopleServiceInternal.class, new LocalService());
     }
 
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index a2e6698..8fc5c08 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -20,6 +20,7 @@
     static_libs: [
         "services.core",
         "services.net",
+        "services.usage",
         "service-jobscheduler",
         "service-permission.impl",
         "service-blobstore",
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index ebd4a4c..f375421 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong;
@@ -44,6 +45,7 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.util.ArraySet;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
@@ -63,6 +65,7 @@
 
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -79,9 +82,11 @@
     private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
     private static final String CALLING_PACKAGE1 = "com.package.name1";
     private static final String CALLING_PACKAGE2 = "com.package.name2";
+    private static final String CALLING_PACKAGE3 = "com.package.name3";
     private static final String NAMESPACE1 = "namespace1";
     private static final String NAMESPACE2 = "namespace2";
     private static final String NAMESPACE3 = "namespace3";
+    private static final String NAMESPACE4 = "namespace4";
     private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
             "persist.device_config.configuration.disable_rescue_party";
     private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
@@ -89,6 +94,8 @@
 
     private MockitoSession mSession;
     private HashMap<String, String> mSystemSettingsMap;
+    //Records the namespaces wiped by setProperties().
+    private HashSet<String> mNamespacesWiped;
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Context mMockContext;
@@ -119,6 +126,7 @@
                         .spyStatic(PackageWatchdog.class)
                         .startMocking();
         mSystemSettingsMap = new HashMap<>();
+        mNamespacesWiped = new HashSet<>();
 
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
         // Reset observer instance to get new mock context on every run
@@ -167,6 +175,16 @@
                         anyBoolean()));
         doAnswer((Answer<Void>) invocationOnMock -> null)
                 .when(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()));
+        doAnswer((Answer<Boolean>) invocationOnMock -> {
+                    DeviceConfig.Properties properties = invocationOnMock.getArgument(0);
+                    String namespace = properties.getNamespace();
+                    // record a wipe
+                    if (properties.getKeyset().isEmpty()) {
+                        mNamespacesWiped.add(namespace);
+                    }
+                    return true;
+                }
+        ).when(() -> DeviceConfig.setProperties(any(DeviceConfig.Properties.class)));
 
         // Mock PackageWatchdog
         doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
@@ -174,8 +192,6 @@
 
         doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
 
-        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL,
-                Integer.toString(RescueParty.LEVEL_NONE));
         SystemProperties.set(RescueParty.PROP_RESCUE_BOOT_COUNT, Integer.toString(0));
         SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
@@ -193,12 +209,10 @@
                 mMonitorCallbackCaptor.capture()));
         HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
 
-        noteBoot();
+        noteBoot(1);
 
         verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
                 verifiedTimesMap);
-        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
-                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
 
         // Record DeviceConfig accesses
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -208,24 +222,19 @@
 
         final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
 
-        noteBoot();
+        noteBoot(2);
 
         verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedAllResetNamespaces,
                 verifiedTimesMap);
-        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
-                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
 
-        noteBoot();
+        noteBoot(3);
 
         verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
                 verifiedTimesMap);
-        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
-                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
 
-        noteBoot();
+        noteBoot(4);
 
-        assertEquals(LEVEL_FACTORY_RESET,
-                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+        assertTrue(RescueParty.isAttemptingFactoryReset());
     }
 
     @Test
@@ -364,24 +373,12 @@
     @Test
     public void testIsAttemptingFactoryReset() {
         for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
-            noteBoot();
+            noteBoot(i + 1);
         }
         assertTrue(RescueParty.isAttemptingFactoryReset());
     }
 
     @Test
-    public void testOnSettingsProviderPublishedExecutesRescueLevels() {
-        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(1));
-
-        RescueParty.onSettingsProviderPublished(mMockContext);
-
-        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
-                /*configResetVerifiedTimesMap=*/ null);
-        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
-                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
-    }
-
-    @Test
     public void testNativeRescuePartyResets() {
         doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed());
         doReturn(FAKE_RESET_NATIVE_NAMESPACES).when(
@@ -425,7 +422,7 @@
         SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true));
 
         for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
-            noteBoot();
+            noteBoot(i + 1);
         }
         assertFalse(RescueParty.isAttemptingFactoryReset());
 
@@ -463,29 +460,128 @@
     public void testBootLoopLevels() {
         RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
 
-        /*
-         Ensure that the returned user impact corresponds with the user impact of the next available
-         rescue level, not the current one.
-         */
-        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
-                RescueParty.LEVEL_NONE));
-        assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_LOW);
+        assertEquals(observer.onBootLoop(0), PackageHealthObserverImpact.USER_IMPACT_NONE);
+        assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LOW);
+        assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LOW);
+        assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+    }
 
-        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
-                RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS));
-        assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_LOW);
+    @Test
+    public void testResetDeviceConfigForPackagesOnlyRuntimeMap() {
+        RescueParty.onSettingsProviderPublished(mMockContext);
+        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+                mMonitorCallbackCaptor.capture()));
 
-        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
-                RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES));
-        assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        // Record DeviceConfig accesses
+        RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+        RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
+        // Fake DeviceConfig value changes
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
 
-        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
-                RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS));
-        assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        doReturn("").when(() -> DeviceConfig.getString(
+                eq(RescueParty.NAMESPACE_CONFIGURATION),
+                eq(RescueParty.NAMESPACE_TO_PACKAGE_MAPPING_FLAG),
+                eq("")));
 
-        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
-                LEVEL_FACTORY_RESET));
-        assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        RescueParty.resetDeviceConfigForPackages(Arrays.asList(new String[]{CALLING_PACKAGE1}));
+        ArraySet<String> expectedNamespacesWiped = new ArraySet<String>(
+                Arrays.asList(new String[]{NAMESPACE1, NAMESPACE2}));
+        assertEquals(mNamespacesWiped, expectedNamespacesWiped);
+    }
+
+    @Test
+    public void testResetDeviceConfigForPackagesOnlyPresetMap() {
+        RescueParty.onSettingsProviderPublished(mMockContext);
+        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+                mMonitorCallbackCaptor.capture()));
+
+        String presetMapping = NAMESPACE1 + ":" + CALLING_PACKAGE1 + ","
+                + NAMESPACE2 + ":" + CALLING_PACKAGE2 + ","
+                + NAMESPACE3 +  ":" + CALLING_PACKAGE1;
+        doReturn(presetMapping).when(() -> DeviceConfig.getString(
+                eq(RescueParty.NAMESPACE_CONFIGURATION),
+                eq(RescueParty.NAMESPACE_TO_PACKAGE_MAPPING_FLAG),
+                eq("")));
+
+        RescueParty.resetDeviceConfigForPackages(Arrays.asList(new String[]{CALLING_PACKAGE1}));
+        ArraySet<String> expectedNamespacesWiped = new ArraySet<String>(
+                Arrays.asList(new String[]{NAMESPACE1, NAMESPACE3}));
+        assertEquals(mNamespacesWiped, expectedNamespacesWiped);
+    }
+
+    @Test
+    public void testResetDeviceConfigForPackagesBothMaps() {
+        RescueParty.onSettingsProviderPublished(mMockContext);
+        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+                mMonitorCallbackCaptor.capture()));
+
+        // Record DeviceConfig accesses
+        RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+        RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE3, NAMESPACE4));
+        // Fake DeviceConfig value changes
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE4));
+
+        String presetMapping = NAMESPACE1 + ":" + CALLING_PACKAGE1 + ","
+                + NAMESPACE2 + ":" + CALLING_PACKAGE2 + ","
+                + NAMESPACE4 + ":" + CALLING_PACKAGE3;
+        doReturn(presetMapping).when(() -> DeviceConfig.getString(
+                eq(RescueParty.NAMESPACE_CONFIGURATION),
+                eq(RescueParty.NAMESPACE_TO_PACKAGE_MAPPING_FLAG),
+                eq("")));
+
+        RescueParty.resetDeviceConfigForPackages(
+                Arrays.asList(new String[]{CALLING_PACKAGE1, CALLING_PACKAGE2}));
+        ArraySet<String> expectedNamespacesWiped = new ArraySet<String>(
+                Arrays.asList(new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3}));
+        assertEquals(mNamespacesWiped, expectedNamespacesWiped);
+    }
+
+    @Test
+    public void testResetDeviceConfigNoExceptionWhenFlagMalformed() {
+        RescueParty.onSettingsProviderPublished(mMockContext);
+        verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+                mMonitorCallbackCaptor.capture()));
+
+        // Record DeviceConfig accesses
+        RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+        RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
+        monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE3, NAMESPACE4));
+        // Fake DeviceConfig value changes
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+        monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE4));
+
+        String invalidPresetMapping = NAMESPACE2 + ":" + CALLING_PACKAGE2 + ","
+                + NAMESPACE1 + "." + CALLING_PACKAGE2;
+        doReturn(invalidPresetMapping).when(() -> DeviceConfig.getString(
+                eq(RescueParty.NAMESPACE_CONFIGURATION),
+                eq(RescueParty.NAMESPACE_TO_PACKAGE_MAPPING_FLAG),
+                eq("")));
+
+        RescueParty.resetDeviceConfigForPackages(
+                Arrays.asList(new String[]{CALLING_PACKAGE1, CALLING_PACKAGE2}));
+        ArraySet<String> expectedNamespacesWiped = new ArraySet<String>(
+                Arrays.asList(new String[]{NAMESPACE1, NAMESPACE3}));
+        assertEquals(mNamespacesWiped, expectedNamespacesWiped);
     }
 
     private void verifySettingsResets(int resetMode, String[] resetNamespaces,
@@ -513,8 +609,8 @@
         }
     }
 
-    private void noteBoot() {
-        RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation();
+    private void noteBoot(int mitigationCount) {
+        RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation(mitigationCount);
     }
 
     private void notePersistentAppCrash(int mitigationCount) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index e48b671..9f895c6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -35,6 +35,8 @@
 import android.os.HandlerThread;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.InstrumentationRegistry;
@@ -181,7 +183,7 @@
 
         boolean parse() {
             try (FileInputStream stream = new FileInputStream(mFile)) {
-                XmlPullParser parser = Xml.newPullParser();
+                TypedXmlPullParser parser = Xml.newFastPullParser();
                 parser.setInput(stream, StandardCharsets.UTF_8.name());
                 int type;
                 while ((type = parser.next()) != XmlPullParser.START_TAG
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java
new file mode 100644
index 0000000..c9fcd02
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/UsageStatsServiceTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usage;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.Context;
+import android.os.RemoteException;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class UsageStatsServiceTest {
+    private static final long TIMEOUT = 5000;
+
+    private UsageStatsService mService;
+
+    private MockitoSession mMockingSession;
+    @Mock
+    private Context mContext;
+
+    private static class TestInjector extends UsageStatsService.Injector {
+        AppStandbyInternal getAppStandbyController(Context context) {
+            return mock(AppStandbyInternal.class);
+        }
+    }
+
+    @Before
+    public void setUp() {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        IActivityManager activityManager = ActivityManager.getService();
+        spyOn(activityManager);
+        try {
+            doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+        } catch (RemoteException e) {
+            fail("registerUidObserver threw exception: " + e.getMessage());
+        }
+        mService = new UsageStatsService(mContext, new TestInjector());
+        spyOn(mService);
+        doNothing().when(mService).publishBinderServices();
+        mService.onStart();
+    }
+
+    @Test
+    public void testUsageEventListener() throws Exception {
+        TestUsageEventListener listener = new TestUsageEventListener();
+        UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
+        usmi.registerListener(listener);
+
+        UsageEvents.Event event = new UsageEvents.Event(UsageEvents.Event.CONFIGURATION_CHANGE, 10);
+        usmi.reportEvent("com.android.test", 10, event.getEventType());
+        listener.setExpectation(10, event);
+        listener.mCountDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
+
+        usmi.unregisterListener(listener);
+        listener.reset();
+
+        usmi.reportEvent("com.android.test", 0, UsageEvents.Event.CHOOSER_ACTION);
+        Thread.sleep(TIMEOUT);
+        assertNull(listener.mLastReceivedEvent);
+    }
+
+    private static class TestUsageEventListener implements
+            UsageStatsManagerInternal.UsageEventListener {
+        UsageEvents.Event mLastReceivedEvent;
+        int mLastReceivedUserId;
+        UsageEvents.Event mExpectedEvent;
+        int mExpectedUserId;
+        CountDownLatch mCountDownLatch;
+
+        @Override
+        public void onUsageEvent(int userId, UsageEvents.Event event) {
+            mLastReceivedUserId = userId;
+            mLastReceivedEvent = event;
+            if (mCountDownLatch != null && userId == mExpectedUserId
+                    && event.getEventType() == mExpectedEvent.getEventType()) {
+                mCountDownLatch.countDown();
+            }
+        }
+
+        private void setExpectation(int userId, UsageEvents.Event event) {
+            mExpectedUserId = userId;
+            mExpectedEvent = event;
+            mCountDownLatch = new CountDownLatch(1);
+        }
+
+        private void reset() {
+            mLastReceivedUserId = mExpectedUserId = -1;
+            mLastReceivedEvent = mExpectedEvent = null;
+            mCountDownLatch = null;
+        }
+    }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index f2bb91c..343b156 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -49,7 +49,8 @@
         // TODO: remove once Android migrates to JUnit 4.12,
         // which provides assertThrows
         "testng",
-
+        "junit",
+        "platform-compat-test-rules",
     ],
 
     aidl: {
@@ -115,6 +116,7 @@
         "utils/**/*.java",
         "utils/**/*.kt",
         "utils-mockito/**/*.kt",
+        ":services.core-sources-deviceconfig-interface",
     ],
     static_libs: [
         "junit",
@@ -131,6 +133,7 @@
         "utils/**/*.java",
         "utils/**/*.kt",
         "utils-mockito/**/*.kt",
+        ":services.core-sources-deviceconfig-interface",
     ],
     static_libs: [
         "junit",
diff --git a/services/tests/servicestests/res/xml/usertypes_test_full.xml b/services/tests/servicestests/res/xml/usertypes_test_full.xml
index a281dca..099ccbe 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_full.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_full.xml
@@ -22,4 +22,7 @@
             <item res='@*android:color/profile_badge_1' />
         </badge-colors>
     </full-type>
+
+    <change-user-type from="android.old.name" to="android.test.1" whenVersionLeq="1" />
+
 </user-types>
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
index b6c8fbd..daa7d7b 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_profile.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<user-types>
+<user-types version="1234">
     <profile-type
         name='android.test.2'
         max-allowed-per-parent='12'
@@ -32,4 +32,7 @@
         <default-restrictions no_remove_user='true' no_bluetooth='true' />
     </profile-type>
     <profile-type name='custom.test.1' max-allowed-per-parent='14' />
+
+    <change-user-type from="android.test.1" to="android.test.2" whenVersionLeq="1233" />
+
 </user-types>
diff --git a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneEventTest.java
similarity index 84%
rename from services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
rename to services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneEventTest.java
index 80373ac..84b886e 100644
--- a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
+++ b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneEventTest.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.location.timezone;
+package com.android.internal.location.timezone;
 
-import static android.location.timezone.ParcelableTestSupport.assertRoundTripParcelable;
+import static com.android.internal.location.timezone.ParcelableTestSupport.assertRoundTripParcelable;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
@@ -29,7 +29,7 @@
 
 public class LocationTimeZoneEventTest {
 
-    private static final long ARBITRARY_ELAPSED_REALTIME_NANOS = 9999;
+    private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 9999;
 
     private static final List<String> ARBITRARY_TIME_ZONE_IDS = singletonList("Europe/London");
 
@@ -42,7 +42,7 @@
     public void testBuildUnsetEventType() {
         new LocationTimeZoneEvent.Builder()
                 .setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
-                .setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
+                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
                 .build();
     }
 
@@ -51,7 +51,7 @@
         new LocationTimeZoneEvent.Builder()
                 .setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
                 .setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
-                .setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
+                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
                 .build();
     }
 
@@ -59,7 +59,7 @@
     public void testEquals() {
         LocationTimeZoneEvent.Builder builder1 = new LocationTimeZoneEvent.Builder()
                 .setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
-                .setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
+                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
         {
             LocationTimeZoneEvent one = builder1.build();
             assertEquals(one, one);
@@ -67,7 +67,7 @@
 
         LocationTimeZoneEvent.Builder builder2 = new LocationTimeZoneEvent.Builder()
                 .setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
-                .setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
+                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
         {
             LocationTimeZoneEvent one = builder1.build();
             LocationTimeZoneEvent two = builder2.build();
@@ -75,7 +75,7 @@
             assertEquals(two, one);
         }
 
-        builder1.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS + 1);
+        builder1.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
         {
             LocationTimeZoneEvent one = builder1.build();
             LocationTimeZoneEvent two = builder2.build();
@@ -83,7 +83,7 @@
             assertNotEquals(two, one);
         }
 
-        builder2.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS + 1);
+        builder2.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
         {
             LocationTimeZoneEvent one = builder1.build();
             LocationTimeZoneEvent two = builder2.build();
@@ -128,7 +128,7 @@
     public void testParcelable() {
         LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
                 .setEventType(LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE)
-                .setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
+                .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
         assertRoundTripParcelable(builder.build());
 
         builder.setEventType(LocationTimeZoneEvent.EVENT_TYPE_SUCCESS)
diff --git a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java
index 75696da..95daa36 100644
--- a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java
+++ b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.location.timezone;
 
-import static android.location.timezone.ParcelableTestSupport.assertRoundTripParcelable;
+import static com.android.internal.location.timezone.ParcelableTestSupport.assertRoundTripParcelable;
 
 import org.junit.Test;
 
diff --git a/services/tests/servicestests/src/android/location/timezone/ParcelableTestSupport.java b/services/tests/servicestests/src/com/android/internal/location/timezone/ParcelableTestSupport.java
similarity index 95%
rename from services/tests/servicestests/src/android/location/timezone/ParcelableTestSupport.java
rename to services/tests/servicestests/src/com/android/internal/location/timezone/ParcelableTestSupport.java
index 316a2e6..ece5d00 100644
--- a/services/tests/servicestests/src/android/location/timezone/ParcelableTestSupport.java
+++ b/services/tests/servicestests/src/com/android/internal/location/timezone/ParcelableTestSupport.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.location.timezone;
+package com.android.internal.location.timezone;
 
 import static org.junit.Assert.assertEquals;
 
@@ -24,7 +24,7 @@
 import java.lang.reflect.Field;
 
 /** Utility methods related to {@link Parcelable} objects used in several tests. */
-public final class ParcelableTestSupport {
+final class ParcelableTestSupport {
 
     private ParcelableTestSupport() {}
 
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index eae4a08..64f3135 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -43,6 +43,8 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.PackageManagerInternal;
+import android.hardware.input.IInputManager;
+import android.hardware.input.InputManager;
 import android.hardware.vibrator.IVibrator;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
@@ -63,11 +65,13 @@
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
+import android.view.InputDevice;
 
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
+import com.android.server.vibrator.VibratorController;
 
 import org.junit.After;
 import org.junit.Before;
@@ -118,8 +122,9 @@
     // TODO(b/131311651): replace with a FakeVibrator instead.
     @Mock private Vibrator mVibratorMock;
     @Mock private AppOpsManager mAppOpsManagerMock;
-    @Mock private VibratorService.NativeWrapper mNativeWrapperMock;
+    @Mock private VibratorController.NativeWrapper mNativeWrapperMock;
     @Mock private IVibratorStateListener mVibratorStateListenerMock;
+    @Mock private IInputManager mIInputManagerMock;
     @Mock private IBinder mVibratorStateListenerBinderMock;
 
     private TestLooper mTestLooper;
@@ -129,10 +134,12 @@
     public void setUp() throws Exception {
         mTestLooper = new TestLooper();
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+        InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
 
         ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
         when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+        when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
         when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock);
         when(mVibratorMock.getDefaultHapticFeedbackIntensity())
                 .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
@@ -145,6 +152,7 @@
                 .thenReturn(new ComponentName("", ""));
         when(mPowerManagerInternalMock.getLowPowerState(PowerManager.ServiceType.VIBRATION))
                 .thenReturn(mPowerSaveStateMock);
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
 
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
@@ -168,8 +176,9 @@
         VibratorService service = new VibratorService(mContextSpy,
                 new VibratorService.Injector() {
                     @Override
-                    VibratorService.NativeWrapper getNativeWrapper() {
-                        return mNativeWrapperMock;
+                    VibratorController createVibratorController(
+                            VibratorController.OnVibrationCompleteListener listener) {
+                        return new VibratorController(0, listener, mNativeWrapperMock);
                     }
 
                     @Override
@@ -189,19 +198,19 @@
     @Test
     public void createService_initializesNativeService() {
         createService();
-        verify(mNativeWrapperMock).vibratorInit(notNull());
-        verify(mNativeWrapperMock).vibratorOff();
+        verify(mNativeWrapperMock).init(eq(0), notNull());
+        verify(mNativeWrapperMock).off();
     }
 
     @Test
     public void hasVibrator_withVibratorHalPresent_returnsTrue() {
-        when(mNativeWrapperMock.vibratorExists()).thenReturn(true);
+        when(mNativeWrapperMock.isAvailable()).thenReturn(true);
         assertTrue(createService().hasVibrator());
     }
 
     @Test
     public void hasVibrator_withNoVibratorHalPresent_returnsFalse() {
-        when(mNativeWrapperMock.vibratorExists()).thenReturn(false);
+        when(mNativeWrapperMock.isAvailable()).thenReturn(false);
         assertFalse(createService().hasVibrator());
     }
 
@@ -217,8 +226,17 @@
     }
 
     @Test
+    public void hasAmplitudeControl_withInputDevices_returnsTrue() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
+        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        assertTrue(createService().hasAmplitudeControl());
+    }
+
+    @Test
     public void areEffectsSupported_withNullResultFromNative_returnsSupportUnknown() {
-        when(mNativeWrapperMock.vibratorGetSupportedEffects()).thenReturn(null);
+        when(mNativeWrapperMock.getSupportedEffects()).thenReturn(null);
         assertArrayEquals(new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN},
                 createService().areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK}));
     }
@@ -227,7 +245,7 @@
     public void areEffectsSupported_withSomeEffectsSupported_returnsSupportYesAndNoForEffects() {
         int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
 
-        when(mNativeWrapperMock.vibratorGetSupportedEffects())
+        when(mNativeWrapperMock.getSupportedEffects())
                 .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
         assertArrayEquals(
                 new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
@@ -247,7 +265,7 @@
     @Test
     public void arePrimitivesSupported_withNullResultFromNative_returnsAlwaysFalse() {
         mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        when(mNativeWrapperMock.vibratorGetSupportedPrimitives()).thenReturn(null);
+        when(mNativeWrapperMock.getSupportedPrimitives()).thenReturn(null);
 
         assertArrayEquals(new boolean[]{false, false},
                 createService().arePrimitivesSupported(new int[]{
@@ -259,7 +277,7 @@
     @Test
     public void arePrimitivesSupported_withSomeSupportedPrimitives_returnsBasedOnNativeResult() {
         mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        when(mNativeWrapperMock.vibratorGetSupportedPrimitives())
+        when(mNativeWrapperMock.getSupportedPrimitives())
                 .thenReturn(new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
 
         assertArrayEquals(new boolean[]{true, false},
@@ -275,7 +293,7 @@
 
         assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
-        verify(mNativeWrapperMock).vibratorAlwaysOnEnable(
+        verify(mNativeWrapperMock).alwaysOnEnable(
                 eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
                 eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
     }
@@ -286,8 +304,8 @@
 
         assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
                 VibrationEffect.createOneShot(100, 255), ALARM_ATTRS));
-        verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
-        verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
+        verify(mNativeWrapperMock, never()).alwaysOnDisable(anyLong());
+        verify(mNativeWrapperMock, never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
     }
 
     @Test
@@ -295,15 +313,15 @@
         mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
 
         assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
-        verify(mNativeWrapperMock).vibratorAlwaysOnDisable(eq(1L));
+        verify(mNativeWrapperMock).alwaysOnDisable(eq(1L));
     }
 
     @Test
     public void setAlwaysOnEffect_withoutCapability_ignoresEffect() {
         assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
                 VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
-        verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
-        verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
+        verify(mNativeWrapperMock, never()).alwaysOnDisable(anyLong());
+        verify(mNativeWrapperMock, never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
     }
 
     @Test
@@ -322,9 +340,9 @@
         vibrate(createService(), VibrationEffect.createOneShot(100, 100), RINGTONE_ATTRS);
 
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock, never()).vibratorOn(eq(1L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(10L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock, never()).on(eq(1L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).on(eq(10L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).on(eq(100L), anyLong());
     }
 
     @Test
@@ -375,6 +393,22 @@
     }
 
     @Test
+    public void vibrate_withOneShotAndInputDevices_vibratesInputDevices() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        VibratorService service = createService();
+        Mockito.clearInvocations(mNativeWrapperMock);
+
+        VibrationEffect effect = VibrationEffect.createOneShot(100, 128);
+        vibrate(service, effect);
+        assertFalse(service.isVibrating());
+
+        verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
+        verify(mNativeWrapperMock, never()).on(anyLong(), anyLong());
+    }
+
+    @Test
     public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
         mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
@@ -383,9 +417,9 @@
         vibrate(service, VibrationEffect.createOneShot(100, 128));
         assertTrue(service.isVibrating());
 
-        verify(mNativeWrapperMock).vibratorOff();
-        verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
-        verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128));
+        verify(mNativeWrapperMock).off();
+        verify(mNativeWrapperMock).on(eq(100L), gt(0L));
+        verify(mNativeWrapperMock).setAmplitude(eq(128));
     }
 
     @Test
@@ -396,26 +430,45 @@
         vibrate(service, VibrationEffect.createOneShot(100, 128));
         assertTrue(service.isVibrating());
 
-        verify(mNativeWrapperMock).vibratorOff();
-        verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
-        verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt());
+        verify(mNativeWrapperMock).off();
+        verify(mNativeWrapperMock).on(eq(100L), gt(0L));
+        verify(mNativeWrapperMock, never()).setAmplitude(anyInt());
     }
 
     @Test
     public void vibrate_withPrebaked_performsEffect() {
-        when(mNativeWrapperMock.vibratorGetSupportedEffects())
+        when(mNativeWrapperMock.getSupportedEffects())
                 .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
         VibratorService service = createService();
         Mockito.clearInvocations(mNativeWrapperMock);
 
         vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
 
-        verify(mNativeWrapperMock).vibratorOff();
-        verify(mNativeWrapperMock).vibratorPerformEffect(eq((long) VibrationEffect.EFFECT_CLICK),
+        verify(mNativeWrapperMock).off();
+        verify(mNativeWrapperMock).perform(eq((long) VibrationEffect.EFFECT_CLICK),
                 eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), gt(0L));
     }
 
     @Test
+    public void vibrate_withPrebakedAndInputDevices_vibratesFallbackWaveformOnInputDevices()
+            throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        VibratorService service = createService();
+        Mockito.clearInvocations(mNativeWrapperMock);
+
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+        assertFalse(service.isVibrating());
+
+        // Wait for VibrateThread to turn input device vibrator ON.
+        Thread.sleep(5);
+        verify(mIInputManagerMock).vibrate(eq(1), any(), any());
+        verify(mNativeWrapperMock, never()).on(anyLong(), anyLong());
+        verify(mNativeWrapperMock, never()).perform(anyLong(), anyLong(), anyLong());
+    }
+
+    @Test
     public void vibrate_withComposed_performsEffect() {
         mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         VibratorService service = createService();
@@ -429,9 +482,8 @@
         ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
                 ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
 
-        verify(mNativeWrapperMock).vibratorOff();
-        verify(mNativeWrapperMock).vibratorPerformComposedEffect(
-                primitivesCaptor.capture(), gt(0L));
+        verify(mNativeWrapperMock).off();
+        verify(mNativeWrapperMock).compose(primitivesCaptor.capture(), gt(0L));
 
         // Check all primitive effect fields are passed down to the HAL.
         assertEquals(1, primitivesCaptor.getValue().length);
@@ -442,6 +494,27 @@
     }
 
     @Test
+    public void vibrate_withComposedAndInputDevices_vibratesInputDevices()
+            throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1, 2});
+        when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
+        when(mIInputManagerMock.getInputDevice(2)).thenReturn(createInputDeviceWithVibrator(2));
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        VibratorService service = createService();
+        Mockito.clearInvocations(mNativeWrapperMock);
+
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
+                .compose();
+        vibrate(service, effect);
+        assertFalse(service.isVibrating());
+
+        verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
+        verify(mIInputManagerMock).vibrate(eq(2), eq(effect), any());
+        verify(mNativeWrapperMock, never()).compose(any(), anyLong());
+    }
+
+    @Test
     public void vibrate_withWaveform_controlsVibratorAmplitudeDuringTotalVibrationTime()
             throws Exception {
         mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
@@ -455,12 +528,12 @@
         // Wait for VibrateThread to finish: 10ms 100, 10ms 200, 10ms 50.
         Thread.sleep(40);
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(30L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorSetAmplitude(eq(200));
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorSetAmplitude(eq(50));
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
+        inOrderVerifier.verify(mNativeWrapperMock).off();
+        inOrderVerifier.verify(mNativeWrapperMock).on(eq(30L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).setAmplitude(eq(100));
+        inOrderVerifier.verify(mNativeWrapperMock).setAmplitude(eq(200));
+        inOrderVerifier.verify(mNativeWrapperMock).setAmplitude(eq(50));
+        inOrderVerifier.verify(mNativeWrapperMock).off();
     }
 
     @Test
@@ -473,12 +546,12 @@
         doAnswer(invocation -> {
             Thread.currentThread().sleep(stepDuration / 4);
             return null;
-        }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
+        }).when(mNativeWrapperMock).on(anyLong(), anyLong());
         // 25% of each waveform step will be spent on the native setAmplitude() call..
         doAnswer(invocation -> {
             Thread.currentThread().sleep(stepDuration / 4);
             return null;
-        }).when(mNativeWrapperMock).vibratorSetAmplitude(anyInt());
+        }).when(mNativeWrapperMock).setAmplitude(anyInt());
 
         VibratorService service = createService();
 
@@ -500,49 +573,71 @@
     }
 
     @Test
+    public void vibrate_withWaveformAndInputDevices_vibratesInputDevices() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        VibratorService service = createService();
+        Mockito.clearInvocations(mNativeWrapperMock);
+
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                new long[]{10, 10, 10}, new int[]{100, 200, 50}, -1);
+        vibrate(service, effect);
+        assertFalse(service.isVibrating());
+
+        // Wait for VibrateThread to turn input device vibrator ON.
+        Thread.sleep(5);
+        verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
+        verify(mNativeWrapperMock, never()).on(anyLong(), anyLong());
+    }
+
+    @Test
     public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() {
         VibratorService service = createService();
         doAnswer(invocation -> {
             service.onVibrationComplete(invocation.getArgument(1));
             return null;
-        }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
+        }).when(mNativeWrapperMock).on(anyLong(), anyLong());
         Mockito.clearInvocations(mNativeWrapperMock);
 
         vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
 
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L),
-                gt(0L));
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
+        inOrderVerifier.verify(mNativeWrapperMock).off();
+        inOrderVerifier.verify(mNativeWrapperMock).on(eq(100L), gt(0L));
+        inOrderVerifier.verify(mNativeWrapperMock).off();
     }
 
     @Test
     public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() {
-        when(mNativeWrapperMock.vibratorGetSupportedEffects())
+        when(mNativeWrapperMock.getSupportedEffects())
                 .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
         VibratorService service = createService();
         doAnswer(invocation -> {
             service.onVibrationComplete(invocation.getArgument(2));
             return 10_000L; // 10s
-        }).when(mNativeWrapperMock).vibratorPerformEffect(anyLong(), anyLong(), anyLong());
+        }).when(mNativeWrapperMock).perform(anyLong(), anyLong(), anyLong());
         Mockito.clearInvocations(mNativeWrapperMock);
 
         vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
 
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect(
+        inOrderVerifier.verify(mNativeWrapperMock).off();
+        inOrderVerifier.verify(mNativeWrapperMock).perform(
                 eq((long) VibrationEffect.EFFECT_CLICK),
                 eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
                 gt(0L));
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
+        inOrderVerifier.verify(mNativeWrapperMock).off();
     }
 
     @Test
-    public void vibrate_withWaveformAndNativeCallback_callbackCannotBeTriggeredByNative()
+    public void vibrate_withWaveformAndNativeCallback_callbackIgnoredAndWaveformPlaysCompletely()
             throws Exception {
         VibratorService service = createService();
+        doAnswer(invocation -> {
+            service.onVibrationComplete(invocation.getArgument(1));
+            return null;
+        }).when(mNativeWrapperMock).on(anyLong(), anyLong());
         Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.createWaveform(new long[]{1, 3, 1, 2}, -1);
@@ -551,10 +646,11 @@
         // Wait for VibrateThread to finish: 1ms OFF, 3ms ON, 1ms OFF, 2ms ON.
         Thread.sleep(15);
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
+        inOrderVerifier.verify(mNativeWrapperMock, times(2)).off();
+        inOrderVerifier.verify(mNativeWrapperMock).on(eq(3L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).off();
+        inOrderVerifier.verify(mNativeWrapperMock).on(eq(2L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).off();
     }
 
     @Test
@@ -564,7 +660,7 @@
         doAnswer(invocation -> {
             service.onVibrationComplete(invocation.getArgument(1));
             return null;
-        }).when(mNativeWrapperMock).vibratorPerformComposedEffect(any(), anyLong());
+        }).when(mNativeWrapperMock).compose(any(), anyLong());
         Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.startComposition()
@@ -573,14 +669,14 @@
         vibrate(service, effect);
 
         InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect(
+        inOrderVerifier.verify(mNativeWrapperMock).off();
+        inOrderVerifier.verify(mNativeWrapperMock).compose(
                 any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L));
-        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
+        inOrderVerifier.verify(mNativeWrapperMock).off();
     }
 
     @Test
-    public void cancelVibrate_withDeviceVibrating_callsVibratorOff() {
+    public void cancelVibrate_withDeviceVibrating_callsoff() {
         VibratorService service = createService();
         vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
         assertTrue(service.isVibrating());
@@ -588,7 +684,7 @@
 
         service.cancelVibrate(service);
         assertFalse(service.isVibrating());
-        verify(mNativeWrapperMock).vibratorOff();
+        verify(mNativeWrapperMock).off();
     }
 
     @Test
@@ -598,24 +694,23 @@
 
         service.cancelVibrate(service);
         assertFalse(service.isVibrating());
-        verify(mNativeWrapperMock, never()).vibratorOff();
+        verify(mNativeWrapperMock, never()).off();
     }
 
     @Test
     public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
         VibratorService service = createService();
-        doAnswer(invocation -> {
-            service.onVibrationComplete(invocation.getArgument(1));
-            return null;
-        }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
         service.registerVibratorStateListener(mVibratorStateListenerMock);
-        verify(mVibratorStateListenerMock).onVibrating(false);
-        Mockito.clearInvocations(mVibratorStateListenerMock);
 
         vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
+        service.cancelVibrate(service);
+
         InOrder inOrderVerifier = inOrder(mVibratorStateListenerMock);
+        // First notification done when listener is registered.
+        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(false);
         inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(true));
         inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(false));
+        inOrderVerifier.verifyNoMoreInteractions();
     }
 
     @Test
@@ -655,16 +750,16 @@
         vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK),
                 RINGTONE_ATTRS);
 
-        verify(mNativeWrapperMock).vibratorPerformEffect(
+        verify(mNativeWrapperMock).perform(
                 eq((long) VibrationEffect.EFFECT_CLICK),
                 eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), anyLong());
-        verify(mNativeWrapperMock).vibratorPerformEffect(
+        verify(mNativeWrapperMock).perform(
                 eq((long) VibrationEffect.EFFECT_TICK),
                 eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), anyLong());
-        verify(mNativeWrapperMock).vibratorPerformEffect(
+        verify(mNativeWrapperMock).perform(
                 eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
                 eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), anyLong());
-        verify(mNativeWrapperMock, never()).vibratorPerformEffect(
+        verify(mNativeWrapperMock, never()).perform(
                 eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), anyLong());
     }
 
@@ -692,14 +787,14 @@
         Thread.sleep(15);
 
         // Alarm vibration is never scaled.
-        verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
+        verify(mNativeWrapperMock).setAmplitude(eq(100));
         // Notification vibrations will be scaled with SCALE_VERY_HIGH.
-        verify(mNativeWrapperMock).vibratorSetAmplitude(intThat(amplitude -> amplitude > 150));
+        verify(mNativeWrapperMock).setAmplitude(intThat(amplitude -> amplitude > 150));
         // Haptic feedback vibrations will be scaled with SCALE_LOW.
-        verify(mNativeWrapperMock).vibratorSetAmplitude(
+        verify(mNativeWrapperMock).setAmplitude(
                 intThat(amplitude -> amplitude < 100 && amplitude > 50));
         // Ringtone vibration is off.
-        verify(mNativeWrapperMock, never()).vibratorSetAmplitude(eq(255));
+        verify(mNativeWrapperMock, never()).setAmplitude(eq(255));
     }
 
     @Test
@@ -729,7 +824,7 @@
         vibrate(service, effect, RINGTONE_ATTRS);
 
         // Ringtone vibration is off, so only the other 3 are propagated to native.
-        verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect(
+        verify(mNativeWrapperMock, times(3)).compose(
                 primitivesCaptor.capture(), anyLong());
 
         List<VibrationEffect.Composition.PrimitiveEffect[]> values =
@@ -788,7 +883,12 @@
     }
 
     private void mockVibratorCapabilities(int capabilities) {
-        when(mNativeWrapperMock.vibratorGetCapabilities()).thenReturn((long) capabilities);
+        when(mNativeWrapperMock.getCapabilities()).thenReturn((long) capabilities);
+    }
+
+    private InputDevice createInputDeviceWithVibrator(int id) {
+        return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
+                null, /* hasVibrator= */ true, false, false);
     }
 
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 904e93b..e2b48d4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -127,6 +127,8 @@
         // Used as an override when set to nonzero.
         private long mCurrentTimeMillis = 0;
 
+        private final Map<Long, Pair<String, Integer>> mEnabledChanges = new ArrayMap<>();
+
         public MockInjector(MockSystemServices services, DpmMockContext context) {
             super(context);
             this.services = services;
@@ -487,5 +489,33 @@
         public long systemCurrentTimeMillis() {
             return mCurrentTimeMillis != 0 ? mCurrentTimeMillis : System.currentTimeMillis();
         }
+
+        public void setChangeEnabledForPackage(
+                long changeId, boolean enabled, String packageName, int userId) {
+            if (enabled) {
+                mEnabledChanges.put(changeId, Pair.create(packageName, userId));
+            } else {
+                mEnabledChanges.remove(changeId);
+            }
+        }
+
+        public void clearEnabledChanges() {
+            mEnabledChanges.clear();
+        }
+
+        @Override
+        public boolean isChangeEnabled(long changeId, String packageName, int userId) {
+            Pair<String, Integer> packageAndUser = mEnabledChanges.get(changeId);
+            if (packageAndUser == null) {
+                return false;
+            }
+
+            if (!packageAndUser.first.equals(packageName)
+                    || !packageAndUser.second.equals(userId)) {
+                return false;
+            }
+
+            return true;
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c0c82d5..77090a8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5090,11 +5090,11 @@
         doReturn(true).when(getServices().lockPatternUtils)
                 .isSeparateProfileChallengeEnabled(managedProfileUserId);
 
-        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
-        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
+        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
+        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
 
         when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
-                .thenReturn(computeForPassword("1234".getBytes()));
+                .thenReturn(computeForPassword("184342".getBytes()));
 
         // Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly
         // on the parent admin)
@@ -5107,6 +5107,68 @@
         managedProfileUserId)).isFalse();
     }
 
+    @Test
+    public void testCanSetPasswordRequirementOnParentPreS() throws Exception {
+        final int managedProfileUserId = CALLER_USER_HANDLE;
+        final int managedProfileAdminUid =
+                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+        mContext.binder.callingUid = managedProfileAdminUid;
+        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
+        dpms.mMockInjector.setChangeEnabledForPackage(165573442L, false,
+                admin1.getPackageName(), managedProfileUserId);
+
+        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+        assertThat(parentDpm.getPasswordQuality(admin1))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+    }
+
+    @Test
+    public void testCannotSetPasswordRequirementOnParent() throws Exception {
+        final int managedProfileUserId = CALLER_USER_HANDLE;
+        final int managedProfileAdminUid =
+                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+        mContext.binder.callingUid = managedProfileAdminUid;
+        addManagedProfile(admin1, managedProfileAdminUid, admin1);
+        dpms.mMockInjector.setChangeEnabledForPackage(165573442L, true,
+                admin1.getPackageName(), managedProfileUserId);
+
+        try {
+            assertExpectException(IllegalArgumentException.class, null, () ->
+                    parentDpm.setPasswordQuality(
+                            admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX));
+        } finally {
+            dpms.mMockInjector.clearEnabledChanges();
+        }
+    }
+
+    @Test
+    public void testPasswordQualityAppliesToParentPreS() throws Exception {
+        final int managedProfileUserId = CALLER_USER_HANDLE;
+        final int managedProfileAdminUid =
+                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+        mContext.binder.callingUid = managedProfileAdminUid;
+        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
+        when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
+                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+
+        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+        assertThat(parentDpm.getPasswordQuality(null))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+    }
+
+    @Test
+    public void testPasswordQualityDoesNotApplyToParentPostS() throws Exception {
+        final int managedProfileUserId = CALLER_USER_HANDLE;
+        final int managedProfileAdminUid =
+                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+        mContext.binder.callingUid = managedProfileAdminUid;
+        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
+
+        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+        assertThat(parentDpm.getPasswordQuality(admin1))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+    }
+
     private void setActivePasswordState(PasswordMetrics passwordMetrics)
             throws Exception {
         final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
@@ -7014,20 +7076,32 @@
      * @param adminUid uid of the admin package.
      * @param copyFromAdmin package information for {@code admin} will be built based on this
      *     component's information.
+     * @param appTargetSdk admin's target SDK level
      */
     private void addManagedProfile(
-            ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
+            ComponentName admin, int adminUid, ComponentName copyFromAdmin, int appTargetSdk)
+            throws Exception {
         final int userId = UserHandle.getUserId(adminUid);
         getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED,
                 UserHandle.USER_SYSTEM);
         mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
-        setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin);
+        setUpPackageManagerForFakeAdmin(admin, adminUid, /* enabledSetting= */ null,
+                appTargetSdk, copyFromAdmin);
         dpm.setActiveAdmin(admin, false, userId);
         assertThat(dpm.setProfileOwner(admin, null, userId)).isTrue();
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
 
     /**
+     * Same as {@code addManagedProfile} above, except using development API level as the API
+     * level of the admin.
+     */
+    private void addManagedProfile(
+            ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
+        addManagedProfile(admin, adminUid, copyFromAdmin, VERSION_CODES.CUR_DEVELOPMENT);
+    }
+
+    /**
      * Convert String[] to StringParceledListSlice.
      */
     private static StringParceledListSlice asSlice(String[] s) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
index 3aa5a80..d58d71f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
@@ -23,6 +23,8 @@
 
 import android.app.admin.FactoryResetProtectionPolicy;
 import android.os.Parcel;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -98,7 +100,7 @@
             throws Exception {
         ByteArrayOutputStream outStream = serialize(policy);
         ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new InputStreamReader(inStream));
         assertThat(parser.next()).isEqualTo(XmlPullParser.START_TAG);
 
@@ -109,7 +111,7 @@
             throws Exception {
         ByteArrayOutputStream outStream = serialize(policy);
         ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
-        XmlPullParser parser = mock(XmlPullParser.class);
+        TypedXmlPullParser parser = mock(TypedXmlPullParser.class);
         when(parser.next()).thenThrow(XmlPullParserException.class);
         parser.setInput(new InputStreamReader(inStream));
 
@@ -120,7 +122,7 @@
     private ByteArrayOutputStream serialize(FactoryResetProtectionPolicy policy)
             throws IOException {
         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
-        final XmlSerializer outXml = new FastXmlSerializer();
+        final TypedXmlSerializer outXml = Xml.newFastSerializer();
         outXml.setOutput(outStream, StandardCharsets.UTF_8.name());
         outXml.startDocument(null, true);
         outXml.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
index 0a9aad7..1308a3e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
@@ -29,6 +29,8 @@
 import android.app.admin.FreezePeriod;
 import android.app.admin.SystemUpdatePolicy;
 import android.os.Parcel;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -471,7 +473,7 @@
 
         // Test XML serialization
         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
-        final XmlSerializer outXml = new FastXmlSerializer();
+        final TypedXmlSerializer outXml = Xml.newFastSerializer();
         outXml.setOutput(outStream, StandardCharsets.UTF_8.name());
         outXml.startDocument(null, true);
         outXml.startTag(null, "ota");
@@ -481,7 +483,7 @@
         outXml.flush();
 
         ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new InputStreamReader(inStream));
         assertThat(parser.next()).isEqualTo(XmlPullParser.START_TAG);
         checkFreezePeriods(SystemUpdatePolicy.restoreFromXml(parser), expectedPeriods);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 026db42..640d6e5 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.PropertyInvalidatedCache;
+import android.compat.testing.PlatformCompatChangeRule;
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -44,8 +45,10 @@
 import android.hardware.input.InputManagerInternal;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Process;
 import android.view.Display;
 import android.view.DisplayCutout;
+import android.view.DisplayEventReceiver;
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -57,13 +60,17 @@
 
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.display.DisplayDeviceInfo;
 import com.android.server.display.DisplayManagerService.SyncRoot;
 import com.android.server.lights.LightsManager;
 import com.android.server.wm.WindowManagerInternal;
 
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -80,6 +87,9 @@
     private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
     private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
 
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
     private Context mContext;
 
     private final DisplayManagerService.Injector mShortMockedInjector =
@@ -95,15 +105,31 @@
                     return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS;
                 }
             };
-    private final DisplayManagerService.Injector mBasicInjector =
-            new DisplayManagerService.Injector() {
+
+    class BasicInjector extends DisplayManagerService.Injector {
+        @Override
+        VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
+                Handler handler, DisplayAdapter.Listener displayAdapterListener) {
+            return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
+                    (String name, boolean secure) -> mMockDisplayToken);
+        }
+    }
+
+    private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
+
+    private final DisplayManagerService.Injector mAllowNonNativeRefreshRateOverrideInjector =
+            new BasicInjector() {
                 @Override
-                VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
-                        Context context, Handler handler,
-                        DisplayAdapter.Listener displayAdapterListener) {
-                    return new VirtualDisplayAdapter(syncRoot, context, handler,
-                            displayAdapterListener,
-                            (String name, boolean secure) -> mMockDisplayToken);
+                boolean getAllowNonNativeRefreshRateOverride() {
+                    return true;
+                }
+            };
+
+    private final DisplayManagerService.Injector mDenyNonNativeRefreshRateOverrideInjector =
+            new BasicInjector() {
+                @Override
+                boolean getAllowNonNativeRefreshRateOverride() {
+                    return false;
                 }
             };
 
@@ -575,6 +601,337 @@
         assertEquals(displayManager.getVirtualDisplaySurfaceInternal(mMockAppToken), surface);
     }
 
+    /**
+     * Tests that there should be a display change notification if the frame rate overrides
+     * list is updated.
+     */
+    @Test
+    public void testShouldNotifyChangeWhenDisplayInfoFrameRateOverrideChanged() throws Exception {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+        registerDefaultDisplays(displayManager);
+        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+        FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager,
+                displayManagerBinderService, displayDevice);
+
+        int myUid = Process.myUid();
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
+                });
+        assertTrue(callback.mCalled);
+        callback.clear();
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
+                        new DisplayEventReceiver.FrameRateOverride(1234, 30f),
+                });
+        assertFalse(callback.mCalled);
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(myUid, 20f),
+                        new DisplayEventReceiver.FrameRateOverride(1234, 30f),
+                        new DisplayEventReceiver.FrameRateOverride(5678, 30f),
+                });
+        assertTrue(callback.mCalled);
+        callback.clear();
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(1234, 30f),
+                        new DisplayEventReceiver.FrameRateOverride(5678, 30f),
+                });
+        assertTrue(callback.mCalled);
+        callback.clear();
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(5678, 30f),
+                });
+        assertFalse(callback.mCalled);
+    }
+
+    /**
+     * Tests that the DisplayInfo is updated correctly with a frame rate override
+     */
+    @Test
+    public void testDisplayInfoFrameRateOverride() throws Exception {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+        registerDefaultDisplays(displayManager);
+        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+                new float[]{60f, 30f, 20f});
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+        DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(
+                                Process.myUid(), 20f),
+                        new DisplayEventReceiver.FrameRateOverride(
+                                Process.myUid() + 1, 30f)
+                });
+        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
+
+        // Changing the mode to 30Hz should not override the refresh rate to 20Hz anymore
+        // as 20 is not a divider of 30.
+        updateModeId(displayManager, displayDevice, 2);
+        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(30f, displayInfo.getRefreshRate(), 0.01f);
+    }
+
+    /**
+     * Tests that the frame rate override is updated accordingly to the
+     * allowNonNativeRefreshRateOverride policy.
+     */
+    @Test
+    public void testDisplayInfoNonNativeFrameRateOverride() throws Exception {
+        testDisplayInfoNonNativeFrameRateOverride(mDenyNonNativeRefreshRateOverrideInjector);
+        testDisplayInfoNonNativeFrameRateOverride(mAllowNonNativeRefreshRateOverrideInjector);
+    }
+
+    /**
+     * Tests that the mode reflects the frame rate override is in compat mode
+     */
+    @Test
+    @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+    public  void testDisplayInfoFrameRateOverrideModeCompat() throws Exception {
+        testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ false);
+    }
+
+    /**
+     * Tests that the mode reflects the physical display refresh rate when not in compat mode.
+     */
+    @Test
+    @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+    public  void testDisplayInfoFrameRateOverrideMode() throws Exception {
+        testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ true);
+    }
+
+    /**
+     * Tests that the mode reflects the frame rate override is in compat mode and accordingly to the
+     * allowNonNativeRefreshRateOverride policy.
+     */
+    @Test
+    @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+    public void testDisplayInfoNonNativeFrameRateOverrideModeCompat() throws Exception {
+        testDisplayInfoNonNativeFrameRateOverrideMode(mDenyNonNativeRefreshRateOverrideInjector,
+                /*compatChangeEnabled*/ false);
+        testDisplayInfoNonNativeFrameRateOverrideMode(mAllowNonNativeRefreshRateOverrideInjector,
+                /*compatChangeEnabled*/  false);
+    }
+
+    /**
+     * Tests that the mode reflects the physical display refresh rate when not in compat mode.
+     */
+    @Test
+    @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
+    public void testDisplayInfoNonNativeFrameRateOverrideMode() throws Exception {
+        testDisplayInfoNonNativeFrameRateOverrideMode(mDenyNonNativeRefreshRateOverrideInjector,
+                /*compatChangeEnabled*/  true);
+        testDisplayInfoNonNativeFrameRateOverrideMode(mAllowNonNativeRefreshRateOverrideInjector,
+                /*compatChangeEnabled*/  true);
+    }
+
+    private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled)
+            throws Exception {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+        registerDefaultDisplays(displayManager);
+        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+                new float[]{60f, 30f, 20f});
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+        DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(
+                                Process.myUid(), 20f),
+                        new DisplayEventReceiver.FrameRateOverride(
+                                Process.myUid() + 1, 30f)
+                });
+        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
+        Display.Mode expectedMode;
+        if (compatChangeEnabled) {
+            expectedMode = new Display.Mode(1, 100, 200, 60f);
+        } else {
+            expectedMode = new Display.Mode(3, 100, 200, 20f);
+        }
+        assertEquals(expectedMode, displayInfo.getMode());
+    }
+
+    private void testDisplayInfoNonNativeFrameRateOverrideMode(
+            DisplayManagerService.Injector injector, boolean compatChangeEnabled) {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, injector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+        registerDefaultDisplays(displayManager);
+        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+                new float[]{60f});
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+        DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(
+                                Process.myUid(), 20f)
+                });
+        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        Display.Mode expectedMode;
+        if (compatChangeEnabled) {
+            expectedMode = new Display.Mode(1, 100, 200, 60f);
+        } else if (injector.getAllowNonNativeRefreshRateOverride()) {
+            expectedMode = new Display.Mode(255, 100, 200, 20f);
+        } else {
+            expectedMode = new Display.Mode(1, 100, 200, 60f);
+        }
+        assertEquals(expectedMode, displayInfo.getMode());
+    }
+
+    private void testDisplayInfoNonNativeFrameRateOverride(
+            DisplayManagerService.Injector injector) {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, injector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+        registerDefaultDisplays(displayManager);
+        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+                new float[]{60f});
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+        DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(
+                                Process.myUid(), 20f)
+                });
+        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        float expectedRefreshRate = injector.getAllowNonNativeRefreshRateOverride() ? 20f : 60f;
+        assertEquals(expectedRefreshRate, displayInfo.getRefreshRate(), 0.01f);
+    }
+
+    private int getDisplayIdForDisplayDevice(
+            DisplayManagerService displayManager,
+            DisplayManagerService.BinderService displayManagerBinderService,
+            FakeDisplayDevice displayDevice) {
+
+        final int[] displayIds = displayManagerBinderService.getDisplayIds();
+        assertTrue(displayIds.length > 0);
+        int displayId = Display.INVALID_DISPLAY;
+        for (int i = 0; i < displayIds.length; i++) {
+            DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]);
+            if (displayDevice.getDisplayDeviceInfoLocked().equals(ddi)) {
+                displayId = displayIds[i];
+                break;
+            }
+        }
+        assertFalse(displayId == Display.INVALID_DISPLAY);
+        return displayId;
+    }
+
+    private void updateDisplayDeviceInfo(DisplayManagerService displayManager,
+            FakeDisplayDevice displayDevice,
+            DisplayDeviceInfo displayDeviceInfo) {
+        displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
+        displayManager.getDisplayDeviceRepository()
+                .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
+        Handler handler = displayManager.getDisplayHandler();
+        handler.runWithScissors(() -> {
+        }, 0 /* now */);
+    }
+
+    private void updateFrameRateOverride(DisplayManagerService displayManager,
+            FakeDisplayDevice displayDevice,
+            DisplayEventReceiver.FrameRateOverride[] frameRateOverrides) {
+        DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+        displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
+        displayDeviceInfo.frameRateOverrides = frameRateOverrides;
+        updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
+    }
+
+    private void updateModeId(DisplayManagerService displayManager,
+            FakeDisplayDevice displayDevice,
+            int modeId) {
+        DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+        displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
+        displayDeviceInfo.modeId = modeId;
+        updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
+    }
+
+    private FakeDisplayManagerCallback registerDisplayListenerCallback(
+            DisplayManagerService displayManager,
+            DisplayManagerService.BinderService displayManagerBinderService,
+            FakeDisplayDevice displayDevice) {
+        // Find the display id of the added FakeDisplayDevice
+        DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
+
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+
+        Handler handler = displayManager.getDisplayHandler();
+        handler.runWithScissors(() -> {
+        }, 0 /* now */);
+
+        // register display listener callback
+        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
+        displayManagerBinderService.registerCallback(callback);
+        return callback;
+    }
+
+    private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
+            float[] refreshRates) {
+        FakeDisplayDevice displayDevice = new FakeDisplayDevice();
+        DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+        int width = 100;
+        int height = 200;
+        displayDeviceInfo.supportedModes = new Display.Mode[refreshRates.length];
+        for (int i = 0; i < refreshRates.length; i++) {
+            displayDeviceInfo.supportedModes[i] =
+                    new Display.Mode(i + 1, width, height, refreshRates[i]);
+        }
+        displayDeviceInfo.modeId = 1;
+        displayDeviceInfo.width = width;
+        displayDeviceInfo.height = height;
+        final Rect zeroRect = new Rect();
+        displayDeviceInfo.displayCutout = new DisplayCutout(
+                Insets.of(0, 10, 0, 0),
+                zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
+        displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
+        displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
+        displayManager.getDisplayDeviceRepository()
+                .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
+        return displayDevice;
+    }
+
     private void registerDefaultDisplays(DisplayManagerService displayManager) {
         Handler handler = displayManager.getDisplayHandler();
         // Would prefer to call displayManager.onStart() directly here but it performs binderService
@@ -598,6 +955,10 @@
                 mCalled = true;
             }
         }
+
+        public void clear() {
+            mCalled = false;
+        }
     }
 
     private class FakeDisplayDevice extends DisplayDevice {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 325ba11..cb5ca04 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -16,49 +16,97 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
+
+import static com.android.server.display.DisplayModeDirector.Vote.PRIORITY_FLICKER;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
 import android.os.Handler;
 import android.os.Looper;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
 import com.android.server.display.DisplayModeDirector.BrightnessObserver;
 import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
 import com.android.server.display.DisplayModeDirector.Vote;
+import com.android.server.testutils.FakeDeviceConfigInterface;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DisplayModeDirectorTest {
     // The tolerance within which we consider something approximately equals.
+    private static final String TAG = "DisplayModeDirectorTest";
+    private static final boolean DEBUG = false;
     private static final float FLOAT_TOLERANCE = 0.01f;
 
     private Context mContext;
+    private FakesInjector mInjector;
+    private Handler mHandler;
+    @Rule
+    public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+        final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
+        when(mContext.getContentResolver()).thenReturn(resolver);
+        mInjector = new FakesInjector();
+        mHandler = new Handler(Looper.getMainLooper());
     }
 
     private DisplayModeDirector createDirectorFromRefreshRateArray(
             float[] refreshRates, int baseModeId) {
         DisplayModeDirector director =
-                new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
+                new DisplayModeDirector(mContext, mHandler, mInjector);
         int displayId = 0;
         Display.Mode[] modes = new Display.Mode[refreshRates.length];
         for (int i = 0; i < refreshRates.length; i++) {
@@ -159,9 +207,9 @@
     }
 
     @Test
-    public void testBrightnessHasLowerPriorityThanUser() {
-        assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
-        assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE);
+    public void testFlickerHasLowerPriorityThanUser() {
+        assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
+        assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE);
 
         int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
@@ -169,7 +217,7 @@
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
         votesByDisplay.put(displayId, votes);
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
-        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+        votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -177,7 +225,7 @@
 
         votes.clear();
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
-        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+        votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
         director.injectVotesByDisplay(votesByDisplay);
         desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
@@ -185,7 +233,7 @@
 
         votes.clear();
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
-        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+        votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
         desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
@@ -193,7 +241,7 @@
 
         votes.clear();
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
-        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+        votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
         director.injectVotesByDisplay(votesByDisplay);
         desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -202,10 +250,10 @@
 
     @Test
     public void testAppRequestRefreshRateRange() {
-        // Confirm that the app request range doesn't include low brightness or min refresh rate
-        // settings, but does include everything else.
+        // Confirm that the app request range doesn't include flicker or min refresh rate settings,
+        // but does include everything else.
         assertTrue(
-                Vote.PRIORITY_LOW_BRIGHTNESS < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+                PRIORITY_FLICKER < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
         assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE
                 < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
         assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
@@ -216,7 +264,7 @@
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
         votesByDisplay.put(displayId, votes);
-        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+        votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -310,7 +358,7 @@
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
         votesByDisplay.put(displayId, votes);
-        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(0, 60));
+        votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(0, 60));
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(60, 90));
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
         votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(60, 60));
@@ -398,4 +446,343 @@
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
         assertThat(desiredSpecs.allowGroupSwitching).isTrue();
     }
+
+    @Test
+    public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() {
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+        SensorManager sensorManager = createMockSensorManager(createLightSensor());
+
+        final int initialRefreshRate = 60;
+        mInjector.getDeviceConfig().setRefreshRateInLowZone(initialRefreshRate);
+        director.start(sensorManager);
+        assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
+                .isEqualTo(initialRefreshRate);
+
+        final int updatedRefreshRate = 90;
+        mInjector.getDeviceConfig().setRefreshRateInLowZone(updatedRefreshRate);
+        // Need to wait for the property change to propagate to the main thread.
+        waitForIdleSync();
+        assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
+                .isEqualTo(updatedRefreshRate);
+    }
+
+    @Test
+    public void testBrightnessObserverThresholdsInZone() {
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+        SensorManager sensorManager = createMockSensorManager(createLightSensor());
+
+        final int[] initialDisplayThresholds = { 10 };
+        final int[] initialAmbientThresholds = { 20 };
+
+        final FakeDeviceConfig config = mInjector.getDeviceConfig();
+        config.setLowDisplayBrightnessThresholds(initialDisplayThresholds);
+        config.setLowAmbientBrightnessThresholds(initialAmbientThresholds);
+        director.start(sensorManager);
+
+        assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
+                .isEqualTo(initialDisplayThresholds);
+        assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
+                .isEqualTo(initialAmbientThresholds);
+
+        final int[] updatedDisplayThresholds = { 9, 14 };
+        final int[] updatedAmbientThresholds = { -1, 19 };
+        config.setLowDisplayBrightnessThresholds(updatedDisplayThresholds);
+        config.setLowAmbientBrightnessThresholds(updatedAmbientThresholds);
+        // Need to wait for the property change to propagate to the main thread.
+        waitForIdleSync();
+        assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
+                .isEqualTo(updatedDisplayThresholds);
+        assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
+                .isEqualTo(updatedAmbientThresholds);
+    }
+
+    @Test
+    public void testLockFpsForLowZone() throws Exception {
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+        setPeakRefreshRate(90);
+        director.getSettingsObserver().setDefaultRefreshRate(90);
+        director.getBrightnessObserver().setDefaultDisplayState(true);
+
+        final FakeDeviceConfig config = mInjector.getDeviceConfig();
+        config.setRefreshRateInLowZone(90);
+        config.setLowDisplayBrightnessThresholds(new int[] { 10 });
+        config.setLowAmbientBrightnessThresholds(new int[] { 20 });
+
+        Sensor lightSensor = createLightSensor();
+        SensorManager sensorManager = createMockSensorManager(lightSensor);
+
+        director.start(sensorManager);
+
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+                .registerListener(
+                        listenerCaptor.capture(),
+                        eq(lightSensor),
+                        anyInt(),
+                        any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        setBrightness(10);
+        // Sensor reads 20 lux,
+        listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/));
+
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+        assertVoteForRefreshRateLocked(vote, 90 /*fps*/);
+
+        setBrightness(125);
+        // Sensor reads 1000 lux,
+        listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/));
+
+        vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+        assertThat(vote).isNull();
+    }
+
+    @Test
+    public void testLockFpsForHighZone() throws Exception {
+        DisplayModeDirector director =
+                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+        setPeakRefreshRate(90 /*fps*/);
+        director.getSettingsObserver().setDefaultRefreshRate(90);
+        director.getBrightnessObserver().setDefaultDisplayState(true);
+
+        final FakeDeviceConfig config = mInjector.getDeviceConfig();
+        config.setRefreshRateInHighZone(60);
+        config.setHighDisplayBrightnessThresholds(new int[] { 255 });
+        config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
+
+        Sensor lightSensor = createLightSensor();
+        SensorManager sensorManager = createMockSensorManager(lightSensor);
+
+        director.start(sensorManager);
+
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+                .registerListener(
+                        listenerCaptor.capture(),
+                        eq(lightSensor),
+                        anyInt(),
+                        any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        setBrightness(100);
+        // Sensor reads 2000 lux,
+        listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000));
+
+        Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+        assertThat(vote).isNull();
+
+        setBrightness(255);
+        // Sensor reads 9000 lux,
+        listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000));
+
+        vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+        assertVoteForRefreshRateLocked(vote, 60 /*fps*/);
+    }
+
+    private void assertVoteForRefreshRateLocked(Vote vote, float refreshRate) {
+        assertThat(vote).isNotNull();
+        final DisplayModeDirector.RefreshRateRange expectedRange =
+                new DisplayModeDirector.RefreshRateRange(refreshRate, refreshRate);
+        assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
+    }
+
+    private static class FakeDeviceConfig extends FakeDeviceConfigInterface {
+        @Override
+        public String getProperty(String namespace, String name) {
+            Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
+            return super.getProperty(namespace, name);
+        }
+
+        @Override
+        public void addOnPropertiesChangedListener(
+                String namespace,
+                Executor executor,
+                DeviceConfig.OnPropertiesChangedListener listener) {
+            Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
+            super.addOnPropertiesChangedListener(namespace, executor, listener);
+        }
+
+        void setRefreshRateInLowZone(int fps) {
+            putPropertyAndNotify(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE,
+                    String.valueOf(fps));
+        }
+
+        void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) {
+            String thresholds = toPropertyValue(brightnessThresholds);
+
+            if (DEBUG) {
+                Slog.e(TAG, "Brightness Thresholds = " + thresholds);
+            }
+
+            putPropertyAndNotify(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS,
+                    thresholds);
+        }
+
+        void setLowAmbientBrightnessThresholds(int[] ambientThresholds) {
+            String thresholds = toPropertyValue(ambientThresholds);
+
+            if (DEBUG) {
+                Slog.e(TAG, "Ambient Thresholds = " + thresholds);
+            }
+
+            putPropertyAndNotify(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS,
+                    thresholds);
+        }
+
+        void setRefreshRateInHighZone(int fps) {
+            putPropertyAndNotify(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE,
+                    String.valueOf(fps));
+        }
+
+        void setHighDisplayBrightnessThresholds(int[] brightnessThresholds) {
+            String thresholds = toPropertyValue(brightnessThresholds);
+
+            if (DEBUG) {
+                Slog.e(TAG, "Brightness Thresholds = " + thresholds);
+            }
+
+            putPropertyAndNotify(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS,
+                    thresholds);
+        }
+
+        void setHighAmbientBrightnessThresholds(int[] ambientThresholds) {
+            String thresholds = toPropertyValue(ambientThresholds);
+
+            if (DEBUG) {
+                Slog.e(TAG, "Ambient Thresholds = " + thresholds);
+            }
+
+            putPropertyAndNotify(
+                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                    KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS,
+                    thresholds);
+        }
+
+        @NonNull
+        private static String toPropertyValue(@NonNull int[] intArray) {
+            return Arrays.stream(intArray)
+                    .mapToObj(Integer::toString)
+                    .collect(Collectors.joining(","));
+        }
+    }
+
+    private void setBrightness(int brightness) {
+        Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
+                brightness);
+        mInjector.notifyBrightnessChanged();
+        waitForIdleSync();
+    }
+
+    private void setPeakRefreshRate(float fps) {
+        Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE,
+                 fps);
+        mInjector.notifyPeakRefreshRateChanged();
+        waitForIdleSync();
+    }
+
+    private static SensorManager createMockSensorManager(Sensor... sensors) {
+        SensorManager sensorManager = Mockito.mock(SensorManager.class);
+        when(sensorManager.getSensorList(anyInt())).then((invocation) -> {
+            List<Sensor> requestedSensors = new ArrayList<>();
+            int type = invocation.getArgument(0);
+            for (Sensor sensor : sensors) {
+                if (sensor.getType() == type || type == Sensor.TYPE_ALL) {
+                    requestedSensors.add(sensor);
+                }
+            }
+            return requestedSensors;
+        });
+
+        when(sensorManager.getDefaultSensor(anyInt())).then((invocation) -> {
+            int type = invocation.getArgument(0);
+            for (Sensor sensor : sensors) {
+                if (sensor.getType() == type) {
+                    return sensor;
+                }
+            }
+            return null;
+        });
+        return sensorManager;
+    }
+
+    private static Sensor createLightSensor() {
+        try {
+            return TestUtils.createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
+        } catch (Exception e) {
+            // There's nothing we can do if this fails, just throw a RuntimeException so that we
+            // don't have to mark every function that might call this as throwing Exception
+            throw new RuntimeException("Failed to create a light sensor", e);
+        }
+    }
+
+    private void waitForIdleSync() {
+        mHandler.runWithScissors(() -> { }, 500 /*timeout*/);
+    }
+
+    static class FakesInjector implements DisplayModeDirector.Injector {
+        private final FakeDeviceConfig mDeviceConfig;
+        private ContentObserver mBrightnessObserver;
+        private ContentObserver mPeakRefreshRateObserver;
+
+        FakesInjector() {
+            mDeviceConfig = new FakeDeviceConfig();
+        }
+
+        @NonNull
+        public FakeDeviceConfig getDeviceConfig() {
+            return mDeviceConfig;
+        }
+
+        @Override
+        public void registerBrightnessObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            if (mBrightnessObserver != null) {
+                throw new IllegalStateException("Tried to register a second brightness observer");
+            }
+            mBrightnessObserver = observer;
+        }
+
+        @Override
+        public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            mBrightnessObserver = null;
+        }
+
+        void notifyBrightnessChanged() {
+            if (mBrightnessObserver != null) {
+                mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI);
+            }
+        }
+
+        @Override
+        public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+                @NonNull ContentObserver observer) {
+            mPeakRefreshRateObserver = observer;
+        }
+
+        void notifyPeakRefreshRateChanged() {
+            if (mPeakRefreshRateObserver != null) {
+                mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
+                        PEAK_REFRESH_RATE_URI);
+            }
+        }
+
+        @Override
+        public boolean isDeviceInteractive(@NonNull Context context) {
+            return true;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index d10e075..de9a5e4 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -18,13 +18,17 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
 
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.hdmi.HdmiControlManager;
+import android.os.Looper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings.Global;
 
@@ -38,15 +42,21 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 @SmallTest
 @Presubmit
 @RunWith(JUnit4.class)
 public final class HdmiCecConfigTest {
     private static final String TAG = "HdmiCecConfigTest";
 
+    private static final int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+
     private Context mContext;
 
     @Mock private HdmiCecConfig.StorageAdapter mStorageAdapter;
+    @Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener;
 
     @Before
     public void setUp() throws Exception {
@@ -1019,4 +1029,105 @@
                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                 Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
     }
+
+    @Test
+    public void registerChangeListener_SharedPref_BasicSanity() {
+        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+                mContext, mStorageAdapter,
+                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+                        + "<cec-settings>"
+                        + "  <setting name=\"system_audio_mode_muting\""
+                        + "           value-type=\"int\""
+                        + "           user-configurable=\"true\">"
+                        + "    <allowed-values>"
+                        + "      <value int-value=\"0\" />"
+                        + "      <value int-value=\"1\" />"
+                        + "    </allowed-values>"
+                        + "    <default-value int-value=\"1\" />"
+                        + "  </setting>"
+                        + "</cec-settings>", null);
+        hdmiCecConfig.registerChangeListener(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                mSettingChangeListener);
+        hdmiCecConfig.setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
+        verify(mSettingChangeListener).onChange(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
+    }
+
+    @Test
+    public void removeChangeListener_SharedPref_BasicSanity() {
+        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+                mContext, mStorageAdapter,
+                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+                        + "<cec-settings>"
+                        + "  <setting name=\"system_audio_mode_muting\""
+                        + "           value-type=\"int\""
+                        + "           user-configurable=\"true\">"
+                        + "    <allowed-values>"
+                        + "      <value int-value=\"0\" />"
+                        + "      <value int-value=\"1\" />"
+                        + "    </allowed-values>"
+                        + "    <default-value int-value=\"1\" />"
+                        + "  </setting>"
+                        + "</cec-settings>", null);
+        hdmiCecConfig.registerChangeListener(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                mSettingChangeListener);
+        hdmiCecConfig.removeChangeListener(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                mSettingChangeListener);
+        hdmiCecConfig.setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
+        verify(mSettingChangeListener, never()).onChange(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
+    }
+
+    /**
+     * Externally modified Global Settings still need to be supported. This test verifies that
+     * setting change notification is being forwarded to listeners registered via HdmiCecConfig.
+     */
+    @Test
+    public void globalSettingObserver_BasicSanity() throws Exception {
+        CountDownLatch notifyLatch = new CountDownLatch(1);
+        // Get current value of the setting in the system.
+        String val = Global.getString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED);
+        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+                mContext, mStorageAdapter,
+                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+                + "<cec-settings>"
+                + "  <setting name=\"hdmi_cec_enabled\""
+                + "           value-type=\"int\""
+                + "           user-configurable=\"true\">"
+                + "    <allowed-values>"
+                + "      <value int-value=\"0\" />"
+                + "      <value int-value=\"1\" />"
+                + "    </allowed-values>"
+                + "    <default-value int-value=\"1\" />"
+                + "  </setting>"
+                + "</cec-settings>", null);
+        hdmiCecConfig.registerGlobalSettingsObserver(Looper.getMainLooper());
+        HdmiCecConfig.SettingChangeListener latchUpdateListener =
+                new HdmiCecConfig.SettingChangeListener() {
+            @Override
+            public void onChange(@NonNull @HdmiControlManager.CecSettingName String setting) {
+                notifyLatch.countDown();
+                assertThat(setting).isEqualTo(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+            }
+        };
+        hdmiCecConfig.registerChangeListener(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                latchUpdateListener);
+        // Flip the value of the setting.
+        Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED,
+                         ((val == null || val.equals("1")) ? "0" : "1"));
+        if (!notifyLatch.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS)) {
+            fail("Timed out waiting for the notify callback");
+        }
+        hdmiCecConfig.unregisterGlobalSettingsObserver();
+        // Restore the previous value of the setting in the system.
+        Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED, val);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 9d767cd..819bd019 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -521,6 +521,41 @@
         assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
     }
 
+    @Test
+    public void initializeCec_14_doesNotBroadcastReportFeatures() {
+        mNativeWrapper.clearResultMessages();
+        mHdmiControlService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                HdmiControlManager.HDMI_CEC_VERSION_1_4_b);
+        mHdmiControlService.setControlEnabled(true);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
+                Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
+                Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
+                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
+                mMyPlaybackDevice.getDeviceFeatures());
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportFeatures);
+    }
+
+    @Test
+    public void initializeCec_20_reportsFeaturesBroadcast() {
+        mHdmiControlService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mHdmiControlService.setControlEnabled(true);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
+                Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
+                Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
+                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
+                mMyPlaybackDevice.getDeviceFeatures());
+        assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
+    }
+
     private static class VolumeControlFeatureCallback extends
             IHdmiCecVolumeControlFeatureListener.Stub {
         boolean mCallbackReceived = false;
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
index 8afc3d3..1db5544 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
@@ -18,6 +18,8 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
@@ -38,9 +40,9 @@
             (displayId) -> {
                 switch (displayId) {
                     case SYSTEM_DECORATION_SUPPORT_DISPLAY_ID:
-                        return true;
+                        return DISPLAY_IME_POLICY_LOCAL;
                     case NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID:
-                        return false;
+                        return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
                     default:
                         throw new IllegalArgumentException("Unknown displayId=" + displayId);
                 }
@@ -49,7 +51,7 @@
     static InputMethodManagerService.ImeDisplayValidator sMustNotBeCalledChecker =
             (displayId) -> {
                 fail("Should not pass to display config check for this test case.");
-                return false;
+                return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
             };
 
     @Test
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 c4b19e8..00cef8f 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
@@ -15,10 +15,9 @@
  */
 package com.android.server.location.timezone;
 
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
-import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
-
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
+import static com.android.internal.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
 import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED;
 import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_CERTAIN;
 import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED_INITIALIZING;
@@ -37,10 +36,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.location.timezone.LocationTimeZoneEvent;
 import android.platform.test.annotations.Presubmit;
 import android.util.IndentingPrintWriter;
 
+import com.android.internal.location.timezone.LocationTimeZoneEvent;
 import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
 import com.android.server.timezonedetector.ConfigurationInternal;
 import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
@@ -60,7 +59,7 @@
 @Presubmit
 public class ControllerImplTest {
 
-    private static final long ARBITRARY_TIME = 12345L;
+    private static final long ARBITRARY_TIME_MILLIS = 12345L;
 
     private static final LocationTimeZoneEvent USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1 =
             createLocationTimeZoneEvent(EVENT_TYPE_SUCCESS, asList("Europe/London"));
@@ -936,7 +935,7 @@
     private static LocationTimeZoneEvent createLocationTimeZoneEvent(
             int eventType, @Nullable List<String> timeZoneIds) {
         LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
-                .setElapsedRealtimeNanos(ARBITRARY_TIME)
+                .setElapsedRealtimeMillis(ARBITRARY_TIME_MILLIS)
                 .setEventType(eventType);
         if (timeZoneIds != null) {
             builder.setTimeZoneIds(timeZoneIds);
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
index 9ef7557..20f9b70 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -27,6 +27,8 @@
 
 import android.content.om.OverlayInfo;
 import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -403,7 +405,7 @@
 
     private int countXmlTags(String xml, String tagToLookFor) throws Exception {
         int count = 0;
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new StringReader(xml));
         int event = parser.getEventType();
         while (event != XmlPullParser.END_DOCUMENT) {
@@ -418,7 +420,7 @@
     private int countXmlAttributesWhere(String xml, String tag, String attr, String value)
             throws Exception {
         int count = 0;
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new StringReader(xml));
         int event = parser.getEventType();
         while (event != XmlPullParser.END_DOCUMENT) {
diff --git a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java
index 9213e1f..a112b14 100644
--- a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java
@@ -69,7 +69,7 @@
         when(mCallback.asBinder()).thenReturn(new Binder());
 
         PeopleService service = new PeopleService(mContext);
-        service.onStart();
+        service.onStart(/* isForTesting= */ true);
 
         mServiceInternal = LocalServices.getService(PeopleServiceInternal.class);
         mLocalService = (PeopleService.LocalService) mServiceInternal;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index bbb83b6..11d00f0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -29,6 +29,8 @@
 import android.util.Slog;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index 89c3d50..90658055 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -25,6 +25,8 @@
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
 import android.util.TypedXmlPullParser;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.InstrumentationRegistry;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 194ae05..23fcf70 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -98,6 +98,8 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.frameworks.servicestests.R;
@@ -8695,7 +8697,7 @@
 
         // Write ShareTargets to Xml
         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
-        final XmlSerializer outXml = new FastXmlSerializer();
+        final TypedXmlSerializer outXml = Xml.newFastSerializer();
         outXml.setOutput(outStream, StandardCharsets.UTF_8.name());
         outXml.startDocument(null, true);
         for (int i = 0; i < expectedValues.size(); i++) {
@@ -8706,7 +8708,7 @@
 
         // Read ShareTargets from Xml
         ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new InputStreamReader(inStream));
         List<ShareTargetInfo> shareTargets = new ArrayList<>();
         int type;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 4fac9dc..dfc25e0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -21,6 +21,7 @@
 import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
 import static android.content.pm.UserInfo.FLAG_FULL;
 import static android.content.pm.UserInfo.FLAG_GUEST;
+import static android.content.pm.UserInfo.FLAG_INITIALIZED;
 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
 import static android.content.pm.UserInfo.FLAG_PROFILE;
 import static android.content.pm.UserInfo.FLAG_RESTRICTED;
@@ -44,6 +45,7 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.text.TextUtils;
 
 import androidx.test.InstrumentationRegistry;
@@ -206,6 +208,8 @@
     @Test
     public void testUpgradeIfNecessaryLP_9() {
         final int versionToTest = 9;
+        // do not trigger a user type upgrade
+        final int userTypeVersion = UserTypeFactory.getUserTypeVersion();
 
         mUserManagerService.putUserInfo(createUser(100, FLAG_MANAGED_PROFILE, null));
         mUserManagerService.putUserInfo(createUser(101,
@@ -216,7 +220,7 @@
         mUserManagerService.putUserInfo(createUser(105, FLAG_SYSTEM | FLAG_FULL, null));
         mUserManagerService.putUserInfo(createUser(106, FLAG_DEMO | FLAG_FULL, null));
 
-        mUserManagerService.upgradeIfNecessaryLP(null, versionToTest - 1);
+        mUserManagerService.upgradeIfNecessaryLP(null, versionToTest - 1, userTypeVersion);
 
         assertTrue(mUserManagerService.isUserOfType(100, USER_TYPE_PROFILE_MANAGED));
         assertTrue((mUserManagerService.getUserInfo(100).flags & FLAG_PROFILE) != 0);
@@ -278,4 +282,86 @@
                     two.convertedFromPreCreated);
         }
     }
+
+    /** Tests upgrading profile types */
+    @Test
+    public void testUpgradeProfileType_updateTypeAndFlags() {
+        final int userId = 42;
+        final String newUserTypeName = "new.user.type";
+        final String oldUserTypeName = USER_TYPE_PROFILE_MANAGED;
+
+        UserTypeDetails.Builder oldUserTypeBuilder = new UserTypeDetails.Builder()
+                .setName(oldUserTypeName)
+                .setBaseType(FLAG_PROFILE)
+                .setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE)
+                .setMaxAllowedPerParent(32)
+                .setIconBadge(401)
+                .setBadgeColors(402, 403, 404)
+                .setBadgeLabels(23, 24, 25);
+        UserTypeDetails oldUserType = oldUserTypeBuilder.createUserTypeDetails();
+
+        UserInfo userInfo = createUser(userId,
+                oldUserType.getDefaultUserInfoFlags() | FLAG_INITIALIZED, oldUserTypeName);
+        mUserManagerService.putUserInfo(userInfo);
+
+        UserTypeDetails.Builder newUserTypeBuilder = new UserTypeDetails.Builder()
+                .setName(newUserTypeName)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowedPerParent(32)
+                .setIconBadge(401)
+                .setBadgeColors(402, 403, 404)
+                .setBadgeLabels(23, 24, 25);
+        UserTypeDetails newUserType = newUserTypeBuilder.createUserTypeDetails();
+
+        mUserManagerService.upgradeProfileToTypeLU(userInfo, newUserType);
+
+        assertTrue(mUserManagerService.isUserOfType(userId, newUserTypeName));
+        assertTrue((mUserManagerService.getUserInfo(userId).flags & FLAG_PROFILE) != 0);
+        assertTrue((mUserManagerService.getUserInfo(userId).flags & FLAG_MANAGED_PROFILE) == 0);
+        assertTrue((mUserManagerService.getUserInfo(userId).flags & FLAG_INITIALIZED) != 0);
+    }
+
+    @Test
+    public void testUpgradeProfileType_updateRestrictions() {
+        final int userId = 42;
+        final String newUserTypeName = "new.user.type";
+        final String oldUserTypeName = USER_TYPE_PROFILE_MANAGED;
+
+        UserTypeDetails.Builder oldUserTypeBuilder = new UserTypeDetails.Builder()
+                .setName(oldUserTypeName)
+                .setBaseType(FLAG_PROFILE)
+                .setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE)
+                .setMaxAllowedPerParent(32)
+                .setIconBadge(401)
+                .setBadgeColors(402, 403, 404)
+                .setBadgeLabels(23, 24, 25);
+        UserTypeDetails oldUserType = oldUserTypeBuilder.createUserTypeDetails();
+
+        UserInfo userInfo = createUser(userId, oldUserType.getDefaultUserInfoFlags(),
+                oldUserTypeName);
+        mUserManagerService.putUserInfo(userInfo);
+        mUserManagerService.setUserRestriction(UserManager.DISALLOW_CAMERA, true, userId);
+        mUserManagerService.setUserRestriction(UserManager.DISALLOW_PRINTING, true, userId);
+
+        UserTypeDetails.Builder newUserTypeBuilder = new UserTypeDetails.Builder()
+                .setName(newUserTypeName)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowedPerParent(32)
+                .setIconBadge(401)
+                .setBadgeColors(402, 403, 404)
+                .setBadgeLabels(23, 24, 25)
+                .setDefaultRestrictions(
+                        UserManagerServiceUserTypeTest.makeRestrictionsBundle(
+                                UserManager.DISALLOW_WALLPAPER));
+        UserTypeDetails newUserType = newUserTypeBuilder.createUserTypeDetails();
+
+        mUserManagerService.upgradeProfileToTypeLU(userInfo, newUserType);
+
+        assertTrue(mUserManagerService.getUserRestrictions(userId).getBoolean(
+                UserManager.DISALLOW_PRINTING));
+        assertTrue(mUserManagerService.getUserRestrictions(userId).getBoolean(
+                UserManager.DISALLOW_CAMERA));
+        assertTrue(mUserManagerService.getUserRestrictions(userId).getBoolean(
+                UserManager.DISALLOW_WALLPAPER));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 8e74c90..ee30f68 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -51,6 +51,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 /**
  * Tests for {@link UserTypeDetails} and {@link UserTypeFactory}.
  *
@@ -358,13 +360,56 @@
                 () -> UserTypeFactory.customizeBuilders(builders, parser));
     }
 
+    @Test
+    public void testUserTypeFactoryVersion_versionMissing() {
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_eraseArray);
+        assertEquals(0, UserTypeFactory.getUserTypeVersion(parser));
+    }
+
+    @Test
+    public void testUserTypeFactoryVersion_versionPresent() {
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
+        assertEquals(1234, UserTypeFactory.getUserTypeVersion(parser));
+    }
+
+    @Test
+    public void testUserTypeFactoryUpgrades_validUpgrades() {
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put("name", getMinimalBuilder());
+
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
+        List<UserTypeFactory.UserTypeUpgrade> upgrades = UserTypeFactory.parseUserUpgrades(builders,
+                parser);
+
+        assertFalse(upgrades.isEmpty());
+        UserTypeFactory.UserTypeUpgrade upgrade = upgrades.get(0);
+        assertEquals("android.test.1", upgrade.getFromType());
+        assertEquals("android.test.2", upgrade.getToType());
+        assertEquals(1233, upgrade.getUpToVersion());
+    }
+
+    @Test
+    public void testUserTypeFactoryUpgrades_illegalBaseTypeUpgrade() {
+        final String userTypeFull = "android.test.1";
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put(userTypeFull, new UserTypeDetails.Builder()
+                .setName(userTypeFull)
+                .setBaseType(FLAG_FULL));
+
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_full);
+
+        // parser is illegal because the "to" upgrade type is not a profile, but a full user
+        assertThrows(IllegalArgumentException.class,
+                () -> UserTypeFactory.parseUserUpgrades(builders, parser));
+    }
+
     /** Returns a minimal {@link UserTypeDetails.Builder} that can legitimately be created. */
     private UserTypeDetails.Builder getMinimalBuilder() {
         return new UserTypeDetails.Builder().setName("name").setBaseType(FLAG_FULL);
     }
 
     /** Creates a Bundle of the given String restrictions, each set to true. */
-    private Bundle makeRestrictionsBundle(String ... restrictions) {
+    public static Bundle makeRestrictionsBundle(String ... restrictions) {
         final Bundle bundle = new Bundle();
         for (String restriction : restrictions) {
             bundle.putBoolean(restriction, true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 3846be0..34cefec 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -134,7 +134,7 @@
 
     private List<SharedLibraryInfo> createMockSharedLibrary(String [] sharedLibrary) {
         SharedLibraryInfo info = new SharedLibraryInfo(null, null, Arrays.asList(sharedLibrary),
-                null, 0L, SharedLibraryInfo.TYPE_STATIC, null, null, null);
+                null, 0L, SharedLibraryInfo.TYPE_STATIC, null, null, null, false /* isNative */);
         ArrayList<SharedLibraryInfo> libraries = new ArrayList<>();
         libraries.add(info);
         return libraries;
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 59aff8d..b26d1efe 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -23,6 +23,10 @@
 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.StateInfo;
+import android.hardware.power.stats.StateResidency;
+import android.hardware.power.stats.StateResidencyResult;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -56,8 +60,13 @@
     private static final String MODEL_FILENAME = "modeltest";
     private static final String PROTO_OUTPUT_FILENAME = "powerstats.proto";
     private static final String CHANNEL_NAME = "channelname";
+    private static final String POWER_ENTITY_NAME = "powerentityinfo";
+    private static final String STATE_NAME = "stateinfo";
     private static final int ENERGY_METER_COUNT = 8;
     private static final int ENERGY_CONSUMER_COUNT = 2;
+    private static final int POWER_ENTITY_COUNT = 3;
+    private static final int STATE_INFO_COUNT = 5;
+    private static final int STATE_RESIDENCY_COUNT = 4;
 
     private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
     private PowerStatsService mService;
@@ -118,6 +127,43 @@
 
     public static final class TestPowerStatsHALWrapper implements IPowerStatsHALWrapper {
         @Override
+        public PowerEntityInfo[] getPowerEntityInfo() {
+            PowerEntityInfo[] powerEntityInfoList = new PowerEntityInfo[POWER_ENTITY_COUNT];
+            for (int i = 0; i < powerEntityInfoList.length; i++) {
+                powerEntityInfoList[i] = new PowerEntityInfo();
+                powerEntityInfoList[i].powerEntityId = i;
+                powerEntityInfoList[i].powerEntityName = new String(POWER_ENTITY_NAME + i);
+                powerEntityInfoList[i].states = new StateInfo[STATE_INFO_COUNT];
+                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);
+                }
+            }
+            return powerEntityInfoList;
+        }
+
+        @Override
+        public StateResidencyResult[] getStateResidency(int[] powerEntityIds) {
+            StateResidencyResult[] stateResidencyResultList =
+                new StateResidencyResult[POWER_ENTITY_COUNT];
+            for (int i = 0; i < stateResidencyResultList.length; i++) {
+                stateResidencyResultList[i] = new StateResidencyResult();
+                stateResidencyResultList[i].powerEntityId = i;
+                stateResidencyResultList[i].stateResidencyData =
+                    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].totalTimeInStateMs = j;
+                    stateResidencyResultList[i].stateResidencyData[j].totalStateEntryCount = j;
+                    stateResidencyResultList[i].stateResidencyData[j].lastEntryTimestampMs = j;
+                }
+            }
+
+            return stateResidencyResultList;
+        }
+
+        @Override
         public int[] getEnergyConsumerInfo() {
             int[] energyConsumerInfoList = new int[ENERGY_CONSUMER_COUNT];
             for (int i = 0; i < energyConsumerInfoList.length; i++) {
@@ -127,7 +173,7 @@
         }
 
         @Override
-        public EnergyConsumerResult[] getEnergyConsumed() {
+        public EnergyConsumerResult[] getEnergyConsumed(int[] energyConsumerIds) {
             EnergyConsumerResult[] energyConsumedList =
                 new EnergyConsumerResult[ENERGY_CONSUMER_COUNT];
             for (int i = 0; i < energyConsumedList.length; i++) {
@@ -151,7 +197,7 @@
         }
 
         @Override
-        public EnergyMeasurement[] readEnergyMeters() {
+        public EnergyMeasurement[] readEnergyMeters(int[] channelIds) {
             EnergyMeasurement[] energyMeasurementList = new EnergyMeasurement[ENERGY_METER_COUNT];
             for (int i = 0; i < energyMeasurementList.length; i++) {
                 energyMeasurementList[i] = new EnergyMeasurement();
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
index eedc978..c42f936 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
@@ -110,6 +110,8 @@
 
     @Rule
     public TemporaryFolder mFolder = new TemporaryFolder();
+    @Rule
+    public TemporaryFolder mHistoryDir = new TemporaryFolder();
 
     private File mRollbackDir;
 
@@ -117,7 +119,7 @@
 
     @Before
     public void setUp() throws Exception {
-        mRollbackStore = new RollbackStore(mFolder.getRoot());
+        mRollbackStore = new RollbackStore(mFolder.getRoot(), mHistoryDir.getRoot());
         mRollbackDir = mFolder.newFolder(ID + "");
         mFolder.newFile("rollback.json");
     }
@@ -202,6 +204,8 @@
         origRb.info.getPackages().add(pkgInfo1);
         origRb.info.getPackages().add(pkgInfo2);
 
+        origRb.setState(Rollback.ROLLBACK_STATE_AVAILABLE, "hello world");
+
         RollbackStore.saveRollback(origRb);
 
         List<Rollback> loadedRollbacks = mRollbackStore.loadRollbacks();
@@ -324,10 +328,26 @@
         assertThat(expectedFile.exists()).isFalse();
     }
 
-    private void assertRollbacksAreEquivalent(Rollback b, Rollback a) {
-        assertThat(b.info.getRollbackId()).isEqualTo(ID);
+    @Test
+    public void saveToHistoryAndLoad() {
+        Rollback origRb = mRollbackStore.createNonStagedRollback(
+                ID, USER, INSTALLER, null, new SparseIntArray(0));
+        mRollbackStore.saveRollbackToHistory(origRb);
 
+        List<Rollback> loadedRollbacks = mRollbackStore.loadHistorialRollbacks();
+        assertThat(loadedRollbacks).hasSize(1);
+        Rollback loadedRb = loadedRollbacks.get(0);
+
+        assertRollbacksAreEquivalentExcludingBackupDir(loadedRb, origRb);
+    }
+
+    private void assertRollbacksAreEquivalent(Rollback b, Rollback a) {
         assertThat(b.getBackupDir()).isEqualTo(a.getBackupDir());
+        assertRollbacksAreEquivalentExcludingBackupDir(b, a);
+    }
+
+    private void assertRollbacksAreEquivalentExcludingBackupDir(Rollback b, Rollback a) {
+        assertThat(b.info.getRollbackId()).isEqualTo(ID);
 
         assertThat(b.isRestoreUserDataInProgress())
                 .isEqualTo(a.isRestoreUserDataInProgress());
@@ -337,6 +357,7 @@
         assertThat(b.isEnabling()).isEqualTo(a.isEnabling());
         assertThat(b.isAvailable()).isEqualTo(a.isAvailable());
         assertThat(b.isCommitted()).isEqualTo(a.isCommitted());
+        assertThat(b.getStateDescription()).isEqualTo(a.getStateDescription());
 
         assertThat(b.isStaged()).isEqualTo(a.isStaged());
 
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index cd2c923..cf1ed48 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -123,7 +123,7 @@
     public void deletedRollbackCannotBeMadeAvailable() {
         Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
 
-        rollback.delete(mMockDataHelper);
+        rollback.delete(mMockDataHelper, "test");
 
         assertThat(rollback.isDeleted()).isTrue();
 
@@ -221,7 +221,7 @@
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
 
-        rollback.delete(mMockDataHelper);
+        rollback.delete(mMockDataHelper, "test");
 
         assertThat(rollback.isDeleted()).isTrue();
 
@@ -247,7 +247,7 @@
 
         verify(mMockDataHelper).snapshotAppData(eq(123), pkgRollbackInfoFor(PKG_2), eq(userIds));
 
-        rollback.delete(mMockDataHelper);
+        rollback.delete(mMockDataHelper, "test");
 
         verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(111));
         verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(222));
@@ -269,7 +269,7 @@
 
         verify(mMockDataHelper).snapshotAppData(eq(123), pkgRollbackInfoFor(PKG_2), eq(userIds));
 
-        rollback.delete(mMockDataHelper);
+        rollback.delete(mMockDataHelper, "test");
 
         verify(mMockDataHelper, never())
                 .destroyAppDataSnapshot(anyInt(), pkgRollbackInfoFor(PKG_2), anyInt());
diff --git a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
index 0f9bf2f..8bccce1 100644
--- a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
+++ b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
@@ -367,7 +367,7 @@
          * for you if needed; if you already have this information around, it can
          * be much more efficient to supply it here.
          * 
-         * @return Returns an XmlPullParser allowing you to parse out the XML
+         * @return Returns an TypedXmlPullParser allowing you to parse out the XML
          * data.  Returns null if the xml resource could not be found for any
          * reason.
          */
diff --git a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
index 1d62e01..7ac4938 100644
--- a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
@@ -21,6 +21,8 @@
 import android.app.usage.CacheQuotaHint;
 import android.test.AndroidTestCase;
 import android.util.Pair;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
 
@@ -37,12 +39,12 @@
 @RunWith(JUnit4.class)
 public class CacheQuotaStrategyTest extends AndroidTestCase {
     StringWriter mWriter;
-    FastXmlSerializer mOut;
+    TypedXmlSerializer mOut;
 
     @Before
     public void setUp() throws Exception {
         mWriter = new StringWriter();
-        mOut = new FastXmlSerializer();
+        mOut = Xml.newFastSerializer();
         mOut.setOutput(mWriter);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 9f59763..4a44005 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -229,10 +229,6 @@
         private boolean mDumpCalled;
 
         @Override
-        public void initialize(Callback ignored) {
-        }
-
-        @Override
         public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
             mLastTelephonySuggestion = timeSuggestion;
         }
@@ -249,7 +245,7 @@
         }
 
         @Override
-        public void handleAutoTimeDetectionChanged() {
+        public void handleAutoTimeConfigChanged() {
             mHandleAutoTimeDetectionChangedCalled = true;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 1d79d0d..c23fb80 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.timedetector;
 
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -25,32 +28,39 @@
 import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.NetworkTimeSuggestion;
 import android.app.timedetector.TelephonyTimeSuggestion;
-import android.icu.util.Calendar;
-import android.icu.util.GregorianCalendar;
-import android.icu.util.TimeZone;
 import android.os.TimestampedValue;
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 
 @RunWith(AndroidJUnit4.class)
 public class TimeDetectorStrategyImplTest {
 
-    private static final TimestampedValue<Long> ARBITRARY_CLOCK_INITIALIZATION_INFO =
+    private static final Instant TIME_LOWER_BOUND = createUtcTime(2009, 1, 1, 12, 0, 0);
+
+    private static final TimestampedValue<Instant> ARBITRARY_CLOCK_INITIALIZATION_INFO =
             new TimestampedValue<>(
                     123456789L /* realtimeClockMillis */,
-                    createUtcTime(2008, 5, 23, 12, 0, 0));
+                    createUtcTime(2010, 5, 23, 12, 0, 0));
+
+    // This is the traditional ordering for time detection on Android.
+    private static final @Origin int [] PROVIDERS_PRIORITY = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
 
     /**
      * An arbitrary time, very different from the {@link #ARBITRARY_CLOCK_INITIALIZATION_INFO}
      * time. Can be used as the basis for time suggestions.
      */
-    private static final long ARBITRARY_TEST_TIME_MILLIS = createUtcTime(2018, 1, 1, 12, 0, 0);
+    private static final Instant ARBITRARY_TEST_TIME = createUtcTime(2018, 1, 1, 12, 0, 0);
 
     private static final int ARBITRARY_SLOT_INDEX = 123456;
 
@@ -67,10 +77,10 @@
                 .pokeAutoTimeDetectionEnabled(true);
 
         int slotIndex = ARBITRARY_SLOT_INDEX;
-        long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+        Instant testTime = ARBITRARY_TEST_TIME;
 
         TelephonyTimeSuggestion timeSuggestion =
-                mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+                mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
         mScript.simulateTimePassing()
                 .simulateTelephonyTimeSuggestion(timeSuggestion);
 
@@ -106,9 +116,9 @@
         // Send the first time signal. It should be used.
         {
             TelephonyTimeSuggestion timeSuggestion1 =
-                    mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME_MILLIS);
+                    mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
 
-            // Increment the the device clocks to simulate the passage of time.
+            // Increment the device clocks to simulate the passage of time.
             mScript.simulateTimePassing(clockIncrementMillis);
 
             long expectedSystemClockMillis1 =
@@ -157,13 +167,13 @@
         // uses the lowest slotIndex when multiple telephony suggestions are available.
         int slotIndex1 = ARBITRARY_SLOT_INDEX;
         int slotIndex2 = ARBITRARY_SLOT_INDEX + 1;
-        long slotIndex1TimeMillis = ARBITRARY_TEST_TIME_MILLIS;
-        long slotIndex2TimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(1).toMillis();
+        Instant slotIndex1Time = ARBITRARY_TEST_TIME;
+        Instant slotIndex2Time = ARBITRARY_TEST_TIME.plus(Duration.ofDays(1));
 
         // Make a suggestion with slotIndex2.
         {
             TelephonyTimeSuggestion slotIndex2TimeSuggestion =
-                    mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
+                    mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
             mScript.simulateTimePassing();
 
             long expectedSystemClockMillis =
@@ -180,7 +190,7 @@
         // Now make a different suggestion with slotIndex1.
         {
             TelephonyTimeSuggestion slotIndex1TimeSuggestion =
-                    mScript.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1TimeMillis);
+                    mScript.generateTelephonyTimeSuggestion(slotIndex1, slotIndex1Time);
             mScript.simulateTimePassing();
 
             long expectedSystemClockMillis =
@@ -198,7 +208,7 @@
         // slotIndex1 suggestion will still "win".
         {
             TelephonyTimeSuggestion slotIndex2TimeSuggestion =
-                    mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
+                    mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
             mScript.simulateTimePassing();
 
             mScript.simulateTelephonyTimeSuggestion(slotIndex2TimeSuggestion)
@@ -213,7 +223,7 @@
         // is in an older "bucket".
         {
             TelephonyTimeSuggestion slotIndex2TimeSuggestion =
-                    mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2TimeMillis);
+                    mScript.generateTelephonyTimeSuggestion(slotIndex2, slotIndex2Time);
             mScript.simulateTimePassing();
 
             long expectedSystemClockMillis =
@@ -232,7 +242,7 @@
 
         int slotIndex = ARBITRARY_SLOT_INDEX;
         TelephonyTimeSuggestion timeSuggestion =
-                mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME_MILLIS);
+                mScript.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
         mScript.simulateTimePassing()
                 .simulateTelephonyTimeSuggestion(timeSuggestion)
                 .verifySystemClockWasNotSetAndResetCallTracking()
@@ -246,11 +256,11 @@
                 .pokeThresholds(systemClockUpdateThreshold)
                 .pokeAutoTimeDetectionEnabled(true);
 
-        long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+        Instant testTime = ARBITRARY_TEST_TIME;
         int slotIndex = ARBITRARY_SLOT_INDEX;
 
         TelephonyTimeSuggestion timeSuggestion1 =
-                mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+                mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
         TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
 
         // Initialize the strategy / device with a time set from a telephony suggestion.
@@ -300,6 +310,23 @@
     }
 
     @Test
+    public void telephonyTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true);
+
+        int slotIndex = ARBITRARY_SLOT_INDEX;
+        Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+
+        TelephonyTimeSuggestion timeSuggestion =
+                mScript.generateTelephonyTimeSuggestion(
+                        slotIndex, suggestedTime);
+
+        mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking()
+                .assertLatestTelephonySuggestion(slotIndex, null);
+    }
+
+    @Test
     public void testSuggestTelephonyTime_timeDetectionToggled() {
         final int clockIncrementMillis = 100;
         final int systemClockUpdateThreshold = 2000;
@@ -308,9 +335,9 @@
                 .pokeAutoTimeDetectionEnabled(false);
 
         int slotIndex = ARBITRARY_SLOT_INDEX;
-        long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+        Instant testTime = ARBITRARY_TEST_TIME;
         TelephonyTimeSuggestion timeSuggestion1 =
-                mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+                mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
         TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
 
         // Simulate time passing.
@@ -366,9 +393,9 @@
                 .pokeAutoTimeDetectionEnabled(true);
 
         int slotIndex = ARBITRARY_SLOT_INDEX;
-        long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+        Instant testTime = ARBITRARY_TEST_TIME;
         TelephonyTimeSuggestion telephonySuggestion =
-                mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+                mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
 
         mScript.simulateTimePassing();
 
@@ -397,7 +424,7 @@
                 .pokeAutoTimeDetectionEnabled(false);
 
         ManualTimeSuggestion timeSuggestion =
-                mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+                mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
 
         mScript.simulateTimePassing();
 
@@ -416,9 +443,9 @@
         int slotIndex = ARBITRARY_SLOT_INDEX;
 
         // Simulate a telephony suggestion.
-        long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
+        Instant testTime = ARBITRARY_TEST_TIME;
         TelephonyTimeSuggestion telephonyTimeSuggestion =
-                mScript.generateTelephonyTimeSuggestion(slotIndex, testTimeMillis);
+                mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
 
         // Simulate the passage of time.
         mScript.simulateTimePassing();
@@ -441,9 +468,9 @@
         mScript.simulateTimePassing();
 
         // Simulate a manual suggestion 1 day different from the auto suggestion.
-        long manualTimeMillis = testTimeMillis + Duration.ofDays(1).toMillis();
+        Instant manualTime = testTime.plus(Duration.ofDays(1));
         ManualTimeSuggestion manualTimeSuggestion =
-                mScript.generateManualTimeSuggestion(manualTimeMillis);
+                mScript.generateManualTimeSuggestion(manualTime);
         mScript.simulateTimePassing();
 
         long expectedManualClockMillis =
@@ -469,16 +496,13 @@
                 .assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
     }
 
-    /**
-     * Manual suggestions should be ignored if auto time is enabled.
-     */
     @Test
-    public void testSuggestManualTime_autoTimeEnabled() {
+    public void manualTimeSuggestion_isIgnored_whenAutoTimeEnabled() {
         mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
                 .pokeAutoTimeDetectionEnabled(true);
 
         ManualTimeSuggestion timeSuggestion =
-                mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+                mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
 
         mScript.simulateTimePassing()
                 .simulateManualTimeSuggestion(timeSuggestion, false /* expectedResult */)
@@ -486,12 +510,25 @@
     }
 
     @Test
+    public void manualTimeSuggestion_ignoresTimeLowerBound() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(false);
+        Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+
+        ManualTimeSuggestion timeSuggestion =
+                mScript.generateManualTimeSuggestion(suggestedTime);
+
+        mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
+                .verifySystemClockWasSetAndResetCallTracking(suggestedTime.toEpochMilli());
+    }
+
+    @Test
     public void testSuggestNetworkTime_autoTimeEnabled() {
         mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
                 .pokeAutoTimeDetectionEnabled(true);
 
         NetworkTimeSuggestion timeSuggestion =
-                mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+                mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
 
         mScript.simulateTimePassing();
 
@@ -507,7 +544,7 @@
                 .pokeAutoTimeDetectionEnabled(false);
 
         NetworkTimeSuggestion timeSuggestion =
-                mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+                mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
 
         mScript.simulateTimePassing()
                 .simulateNetworkTimeSuggestion(timeSuggestion)
@@ -520,16 +557,16 @@
                 .pokeAutoTimeDetectionEnabled(true);
 
         // Three obviously different times that could not be mistaken for each other.
-        long networkTimeMillis1 = ARBITRARY_TEST_TIME_MILLIS;
-        long networkTimeMillis2 = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(30).toMillis();
-        long telephonyTimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(60).toMillis();
+        Instant networkTime1 = ARBITRARY_TEST_TIME;
+        Instant networkTime2 = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+        Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(60));
         // A small increment used to simulate the passage of time, but not enough to interfere with
         // macro-level time changes associated with suggestion age.
         final long smallTimeIncrementMillis = 101;
 
         // A network suggestion is made. It should be used because there is no telephony suggestion.
         NetworkTimeSuggestion networkTimeSuggestion1 =
-                mScript.generateNetworkTimeSuggestion(networkTimeMillis1);
+                mScript.generateNetworkTimeSuggestion(networkTime1);
         mScript.simulateTimePassing(smallTimeIncrementMillis)
                 .simulateNetworkTimeSuggestion(networkTimeSuggestion1)
                 .verifySystemClockWasSetAndResetCallTracking(
@@ -548,7 +585,7 @@
         // Now a telephony suggestion is made. Telephony suggestions are prioritized over network
         // suggestions so it should "win".
         TelephonyTimeSuggestion telephonyTimeSuggestion =
-                mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeMillis);
+                mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
         mScript.simulateTimePassing(smallTimeIncrementMillis)
                 .simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
                 .verifySystemClockWasSetAndResetCallTracking(
@@ -568,7 +605,7 @@
         // Now another network suggestion is made. Telephony suggestions are prioritized over
         // network suggestions so the latest telephony suggestion should still "win".
         NetworkTimeSuggestion networkTimeSuggestion2 =
-                mScript.generateNetworkTimeSuggestion(networkTimeMillis2);
+                mScript.generateNetworkTimeSuggestion(networkTime2);
         mScript.simulateTimePassing(smallTimeIncrementMillis)
                 .simulateNetworkTimeSuggestion(networkTimeSuggestion2)
                 .verifySystemClockWasNotSetAndResetCallTracking();
@@ -612,16 +649,98 @@
         assertNull(mScript.peekBestTelephonySuggestion());
     }
 
+    @Test
+    public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true);
+
+        Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+        NetworkTimeSuggestion timeSuggestion = mScript
+                .generateNetworkTimeSuggestion(suggestedTime);
+
+        mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking()
+                .assertLatestNetworkSuggestion(null);
+    }
+
+    @Test
+    public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_lowerPriorityComesFirst() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true);
+
+        Instant networkTime = ARBITRARY_TEST_TIME;
+        Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+
+        NetworkTimeSuggestion networkTimeSuggestion =
+                mScript.generateNetworkTimeSuggestion(networkTime);
+        TelephonyTimeSuggestion telephonyTimeSuggestion =
+                mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+
+        mScript.simulateNetworkTimeSuggestion(networkTimeSuggestion)
+                .simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
+                .assertLatestNetworkSuggestion(networkTimeSuggestion)
+                .assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(telephonyTime.toEpochMilli());
+    }
+
+    @Test
+    public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_higherPriorityComesFirst() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true);
+
+        Instant networkTime = ARBITRARY_TEST_TIME;
+        Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+
+        NetworkTimeSuggestion networkTimeSuggestion =
+                mScript.generateNetworkTimeSuggestion(networkTime);
+        TelephonyTimeSuggestion telephonyTimeSuggestion =
+                mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+
+        mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
+                .simulateNetworkTimeSuggestion(networkTimeSuggestion)
+                .assertLatestNetworkSuggestion(networkTimeSuggestion)
+                .assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(telephonyTime.toEpochMilli());
+    }
+
+    @Test
+    public void whenHighestPrioritySuggestionIsNotAvailable_fallbacksToNext() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true);
+
+        NetworkTimeSuggestion timeSuggestion =
+                mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
+
+        mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+                .assertLatestNetworkSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
+    }
+
+    @Test
+    public void suggestionsFromSourceNotListedInPrioritiesList_areIgnored() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true)
+                .pokeAutoOriginPriorities(new int[]{ORIGIN_TELEPHONY});
+
+        NetworkTimeSuggestion timeSuggestion = mScript.generateNetworkTimeSuggestion(
+                ARBITRARY_TEST_TIME);
+
+        mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+                .assertLatestNetworkSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
     /**
      * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
      * like the real thing should, it also asserts preconditions.
      */
-    private static class FakeCallback implements TimeDetectorStrategy.Callback {
+    private static class FakeCallback implements TimeDetectorStrategyImpl.Callback {
         private boolean mAutoTimeDetectionEnabled;
         private boolean mWakeLockAcquired;
         private long mElapsedRealtimeMillis;
         private long mSystemClockMillis;
         private int mSystemClockUpdateThresholdMillis = 2000;
+        private int[] mAutoOriginPriorities = PROVIDERS_PRIORITY;
 
         // Tracking operations.
         private boolean mSystemClockWasSet;
@@ -637,6 +756,16 @@
         }
 
         @Override
+        public Instant autoTimeLowerBound() {
+            return TIME_LOWER_BOUND;
+        }
+
+        @Override
+        public int[] getAutoOriginPriorities() {
+            return mAutoOriginPriorities;
+        }
+
+        @Override
         public void acquireWakeLock() {
             if (mWakeLockAcquired) {
                 fail("Wake lock already acquired");
@@ -685,6 +814,10 @@
             mAutoTimeDetectionEnabled = enabled;
         }
 
+        void pokeAutoOriginPriorities(@Origin int[] autoOriginPriorities) {
+            mAutoOriginPriorities = autoOriginPriorities;
+        }
+
         long peekElapsedRealtimeMillis() {
             return mElapsedRealtimeMillis;
         }
@@ -703,7 +836,10 @@
         }
 
         void verifySystemClockNotSet() {
-            assertFalse(mSystemClockWasSet);
+            assertFalse(
+                    String.format("System clock was manipulated and set to %s(=%s)",
+                            Instant.ofEpochMilli(mSystemClockMillis), mSystemClockMillis),
+                    mSystemClockWasSet);
         }
 
         void verifySystemClockWasSet(long expectedSystemClockMillis) {
@@ -731,9 +867,7 @@
 
         Script() {
             mFakeCallback = new FakeCallback();
-            mTimeDetectorStrategy = new TimeDetectorStrategyImpl();
-            mTimeDetectorStrategy.initialize(mFakeCallback);
-
+            mTimeDetectorStrategy = new TimeDetectorStrategyImpl(mFakeCallback);
         }
 
         Script pokeAutoTimeDetectionEnabled(boolean enabled) {
@@ -741,9 +875,9 @@
             return this;
         }
 
-        Script pokeFakeClocks(TimestampedValue<Long> timeInfo) {
+        Script pokeFakeClocks(TimestampedValue<Instant> timeInfo) {
             mFakeCallback.pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis());
-            mFakeCallback.pokeSystemClockMillis(timeInfo.getValue());
+            mFakeCallback.pokeSystemClockMillis(timeInfo.getValue().toEpochMilli());
             return this;
         }
 
@@ -752,6 +886,11 @@
             return this;
         }
 
+        Script pokeAutoOriginPriorities(@Origin int[] autoOriginPriorites) {
+            mFakeCallback.pokeAutoOriginPriorities(autoOriginPriorites);
+            return this;
+        }
+
         long peekElapsedRealtimeMillis() {
             return mFakeCallback.peekElapsedRealtimeMillis();
         }
@@ -767,7 +906,13 @@
 
         Script simulateManualTimeSuggestion(
                 ManualTimeSuggestion timeSuggestion, boolean expectedResult) {
-            assertEquals(expectedResult, mTimeDetectorStrategy.suggestManualTime(timeSuggestion));
+            String errorMessage = expectedResult
+                    ? "Manual time suggestion was ignored, but expected to be accepted."
+                    : "Manual time suggestion was accepted, but expected to be ignored.";
+            assertEquals(
+                    errorMessage,
+                    expectedResult,
+                    mTimeDetectorStrategy.suggestManualTime(timeSuggestion));
             return this;
         }
 
@@ -778,7 +923,7 @@
 
         Script simulateAutoTimeDetectionToggle() {
             mFakeCallback.simulateAutoTimeZoneDetectionToggle();
-            mTimeDetectorStrategy.handleAutoTimeDetectionChanged();
+            mTimeDetectorStrategy.handleAutoTimeConfigChanged();
             return this;
         }
 
@@ -810,7 +955,10 @@
          * White box test info: Asserts the latest suggestion for the slotIndex is as expected.
          */
         Script assertLatestTelephonySuggestion(int slotIndex, TelephonyTimeSuggestion expected) {
-            assertEquals(expected, mTimeDetectorStrategy.getLatestTelephonySuggestion(slotIndex));
+            assertEquals(
+                    "Expected to see " + expected + " at slotIndex=" + slotIndex + ", but got "
+                            + mTimeDetectorStrategy.getLatestTelephonySuggestion(slotIndex),
+                    expected, mTimeDetectorStrategy.getLatestTelephonySuggestion(slotIndex));
             return this;
         }
 
@@ -842,9 +990,11 @@
          * Generates a ManualTimeSuggestion using the current elapsed realtime clock for the
          * reference time.
          */
-        ManualTimeSuggestion generateManualTimeSuggestion(long timeMillis) {
+        ManualTimeSuggestion generateManualTimeSuggestion(Instant suggestedTime) {
             TimestampedValue<Long> utcTime =
-                    new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis);
+                    new TimestampedValue<>(
+                            mFakeCallback.peekElapsedRealtimeMillis(),
+                            suggestedTime.toEpochMilli());
             return new ManualTimeSuggestion(utcTime);
         }
 
@@ -852,21 +1002,33 @@
          * Generates a {@link TelephonyTimeSuggestion} using the current elapsed realtime clock for
          * the reference time.
          */
-        TelephonyTimeSuggestion generateTelephonyTimeSuggestion(int slotIndex, Long timeMillis) {
-            TimestampedValue<Long> time = null;
-            if (timeMillis != null) {
-                time = new TimestampedValue<>(peekElapsedRealtimeMillis(), timeMillis);
-            }
+        TelephonyTimeSuggestion generateTelephonyTimeSuggestion(int slotIndex, long timeMillis) {
+            TimestampedValue<Long> time =
+                    new TimestampedValue<>(peekElapsedRealtimeMillis(), timeMillis);
             return createTelephonyTimeSuggestion(slotIndex, time);
         }
 
         /**
+         * Generates a {@link TelephonyTimeSuggestion} using the current elapsed realtime clock for
+         * the reference time.
+         */
+        TelephonyTimeSuggestion generateTelephonyTimeSuggestion(
+                int slotIndex, Instant suggestedTime) {
+            if (suggestedTime == null) {
+                return createTelephonyTimeSuggestion(slotIndex, null);
+            }
+            return generateTelephonyTimeSuggestion(slotIndex, suggestedTime.toEpochMilli());
+        }
+
+        /**
          * Generates a NetworkTimeSuggestion using the current elapsed realtime clock for the
          * reference time.
          */
-        NetworkTimeSuggestion generateNetworkTimeSuggestion(long timeMillis) {
+        NetworkTimeSuggestion generateNetworkTimeSuggestion(Instant suggestedTime) {
             TimestampedValue<Long> utcTime =
-                    new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis);
+                    new TimestampedValue<>(
+                            mFakeCallback.peekElapsedRealtimeMillis(),
+                            suggestedTime.toEpochMilli());
             return new NetworkTimeSuggestion(utcTime);
         }
 
@@ -886,11 +1048,9 @@
                 .build();
     }
 
-    private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
-            int second) {
-        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
-        cal.clear();
-        cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
-        return cal.getTimeInMillis();
+    private static Instant createUtcTime(int year, int monthInYear, int day, int hourOfDay,
+            int minute, int second) {
+        return LocalDateTime.of(year, monthInYear, day, hourOfDay, minute, second)
+                .toInstant(ZoneOffset.UTC);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 0ad669f..11fb002 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -65,6 +65,7 @@
 import android.app.ActivityManager;
 import android.app.usage.AppStandbyInfo;
 import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -86,9 +87,11 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -425,11 +428,18 @@
 
     @Before
     public void setUp() throws Exception {
+        LocalServices.addService(
+                UsageStatsManagerInternal.class, mock(UsageStatsManagerInternal.class));
         MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
         mInjector = new MyInjector(myContext, Looper.getMainLooper());
         mController = setupController();
     }
 
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+    }
+
     @Test
     public void testBoundWidgetPackageExempt() throws Exception {
         assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
@@ -562,7 +572,7 @@
         UsageEvents.Event ev = new UsageEvents.Event();
         ev.mPackage = packageName;
         ev.mEventType = eventType;
-        controller.reportEvent(ev, USER_ID);
+        controller.onUsageEvent(USER_ID, ev);
     }
 
     private int getStandbyBucket(AppStandbyController controller, String packageName) {
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
new file mode 100644
index 0000000..fa8e367
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.hardware.input.IInputDevicesChangedListener;
+import android.hardware.input.IInputManager;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.Process;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.view.InputDevice;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Tests for {@link InputDeviceDelegate}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:InputDeviceDelegateTest
+ */
+@Presubmit
+public class InputDeviceDelegateTest {
+
+    private static final int UID = Process.ROOT_UID;
+    private static final String PACKAGE_NAME = "package";
+    private static final String REASON = "some reason";
+    private static final VibrationAttributes VIBRATION_ATTRIBUTES =
+            new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build();
+
+    @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock private IInputManager mIInputManagerMock;
+
+    private TestLooper mTestLooper;
+    private ContextWrapper mContextSpy;
+    private InputDeviceDelegate mInputDeviceDelegate;
+    private IInputDevicesChangedListener mIInputDevicesChangedListener;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+        InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
+
+        when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
+        doAnswer(invocation -> mIInputDevicesChangedListener = invocation.getArgument(0))
+                .when(mIInputManagerMock).registerInputDevicesChangedListener(any());
+
+        mInputDeviceDelegate = new InputDeviceDelegate(
+                mContextSpy, new Handler(mTestLooper.getLooper()));
+    }
+
+    @Test
+    public void onInputDeviceAdded_withSettingsDisabled_ignoresNewDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ false);
+        assertFalse(mInputDeviceDelegate.isAvailable());
+
+        when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
+        mInputDeviceDelegate.onInputDeviceAdded(1);
+
+        assertFalse(mInputDeviceDelegate.isAvailable());
+        verify(mIInputManagerMock, never()).getInputDevice(anyInt());
+    }
+
+    @Test
+    public void onInputDeviceAdded_withDeviceWithoutVibrator_ignoresNewDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertFalse(mInputDeviceDelegate.isAvailable());
+
+        when(mIInputManagerMock.getInputDevice(eq(1)))
+                .thenReturn(createInputDeviceWithoutVibrator(1));
+        updateInputDevices(new int[]{1});
+
+        assertFalse(mInputDeviceDelegate.isAvailable());
+        verify(mIInputManagerMock).getInputDevice(eq(1));
+    }
+
+    @Test
+    public void onInputDeviceAdded_withDeviceWithVibrator_addsNewDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertFalse(mInputDeviceDelegate.isAvailable());
+
+        when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
+        updateInputDevices(new int[]{1});
+
+        assertTrue(mInputDeviceDelegate.isAvailable());
+        verify(mIInputManagerMock).getInputDevice(eq(1));
+    }
+
+    @Test
+    public void onInputDeviceChanged_withSettingsDisabled_ignoresDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ false);
+
+        updateInputDevices(new int[]{1});
+        assertFalse(mInputDeviceDelegate.isAvailable());
+        verify(mIInputManagerMock, never()).getInputDevice(anyInt());
+    }
+
+    @Test
+    public void onInputDeviceChanged_deviceLosesVibrator_removesDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(eq(1)))
+                .thenReturn(createInputDeviceWithVibrator(1), createInputDeviceWithoutVibrator(1));
+
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertTrue(mInputDeviceDelegate.isAvailable());
+
+        updateInputDevices(new int[]{1});
+        assertFalse(mInputDeviceDelegate.isAvailable());
+        verify(mIInputManagerMock, times(2)).getInputDevice(eq(1));
+    }
+
+    @Test
+    public void onInputDeviceChanged_deviceLost_removesDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(eq(1)))
+                .thenReturn(createInputDeviceWithVibrator(1), (InputDevice) null);
+
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertTrue(mInputDeviceDelegate.isAvailable());
+
+        updateInputDevices(new int[]{1});
+        assertFalse(mInputDeviceDelegate.isAvailable());
+        verify(mIInputManagerMock, times(2)).getInputDevice(eq(1));
+    }
+
+    @Test
+    public void onInputDeviceChanged_deviceAddsVibrator_addsDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(eq(1)))
+                .thenReturn(createInputDeviceWithoutVibrator(1), createInputDeviceWithVibrator(1));
+
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertFalse(mInputDeviceDelegate.isAvailable());
+
+        updateInputDevices(new int[]{1});
+        assertTrue(mInputDeviceDelegate.isAvailable());
+        verify(mIInputManagerMock, times(2)).getInputDevice(eq(1));
+    }
+
+    @Test
+    public void onInputDeviceRemoved_removesDevice() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1, 2});
+        when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(
+                createInputDeviceWithoutVibrator(1));
+        when(mIInputManagerMock.getInputDevice(eq(2))).thenReturn(createInputDeviceWithVibrator(2));
+
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertTrue(mInputDeviceDelegate.isAvailable());
+
+        updateInputDevices(new int[]{1});
+        assertFalse(mInputDeviceDelegate.isAvailable());
+    }
+
+    @Test
+    public void updateInputDeviceVibrators_usesFlagToLoadDeviceList() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1, 2});
+        when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
+        when(mIInputManagerMock.getInputDevice(eq(2))).thenReturn(createInputDeviceWithVibrator(2));
+
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertTrue(mInputDeviceDelegate.isAvailable());
+
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ false);
+        assertFalse(mInputDeviceDelegate.isAvailable());
+    }
+
+    @Test
+    public void updateInputDeviceVibrators_withDeviceWithoutVibrator_deviceIsIgnored()
+            throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
+        when(mIInputManagerMock.getInputDevice(eq(1)))
+                .thenReturn(createInputDeviceWithoutVibrator(1));
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertFalse(mInputDeviceDelegate.isAvailable());
+    }
+
+    @Test
+    public void vibrateIfAvailable_withNoInputDevice_returnsFalse() {
+        VibrationEffect effect = VibrationEffect.createOneShot(100, 255);
+        assertFalse(mInputDeviceDelegate.isAvailable());
+        assertFalse(mInputDeviceDelegate.vibrateIfAvailable(
+                UID, PACKAGE_NAME, effect, REASON, VIBRATION_ATTRIBUTES));
+    }
+
+    @Test
+    public void vibrateIfAvailable_withInputDevices_returnsTrueAndVibratesAllDevices()
+            throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1, 2});
+        when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
+        when(mIInputManagerMock.getInputDevice(eq(2))).thenReturn(createInputDeviceWithVibrator(2));
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+
+        VibrationEffect effect = VibrationEffect.createOneShot(100, 255);
+        assertTrue(mInputDeviceDelegate.vibrateIfAvailable(
+                UID, PACKAGE_NAME, effect, REASON, VIBRATION_ATTRIBUTES));
+        verify(mIInputManagerMock).vibrate(eq(1), same(effect), any());
+        verify(mIInputManagerMock).vibrate(eq(2), same(effect), any());
+    }
+
+    @Test
+    public void cancelVibrateIfAvailable_withNoInputDevice_returnsFalse() throws Exception {
+        assertFalse(mInputDeviceDelegate.isAvailable());
+        assertFalse(mInputDeviceDelegate.cancelVibrateIfAvailable());
+        verify(mIInputManagerMock, never()).cancelVibrate(anyInt(), any());
+    }
+
+    @Test
+    public void cancelVibrateIfAvailable_withInputDevices_returnsTrueAndStopsAllDevices()
+            throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1, 2});
+        when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
+        when(mIInputManagerMock.getInputDevice(eq(2))).thenReturn(createInputDeviceWithVibrator(2));
+        mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+
+        assertTrue(mInputDeviceDelegate.isAvailable());
+        assertTrue(mInputDeviceDelegate.cancelVibrateIfAvailable());
+        verify(mIInputManagerMock).cancelVibrate(eq(1), any());
+        verify(mIInputManagerMock).cancelVibrate(eq(2), any());
+    }
+
+    private void updateInputDevices(int[] deviceIds) throws Exception {
+        int[] deviceIdsAndGenerations = new int[deviceIds.length * 2];
+        for (int i = 0; i < deviceIdsAndGenerations.length; i += 2) {
+            deviceIdsAndGenerations[i] = deviceIds[i / 2];
+            deviceIdsAndGenerations[i + 1] = 2; // update by increasing it's generation to 2.
+        }
+        // Force initialization of mIInputDevicesChangedListener, if it still haven't
+        InputManager.getInstance().getInputDeviceIds();
+        mIInputDevicesChangedListener.onInputDevicesChanged(deviceIdsAndGenerations);
+        // Makes sure all callbacks from InputDeviceDelegate are executed.
+        mTestLooper.dispatchAll();
+    }
+
+    private InputDevice createInputDeviceWithVibrator(int id) {
+        return createInputDevice(id, /* hasVibrator= */ true);
+    }
+
+    private InputDevice createInputDeviceWithoutVibrator(int id) {
+        return createInputDevice(id, /* hasVibrator= */ false);
+    }
+
+    private InputDevice createInputDevice(int id, boolean hasVibrator) {
+        return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
+                null, hasVibrator, false, false);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index 2cc9992..04c2cb3 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.spy;
@@ -33,6 +34,7 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
@@ -271,6 +273,15 @@
                 mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
     }
 
+    @Test
+    public void getFallbackEffect_returnsEffectsFromSettings() {
+        assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_TICK));
+        assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_TEXTURE_TICK));
+        assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_CLICK));
+        assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_HEAVY_CLICK));
+        assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_DOUBLE_CLICK));
+    }
+
     private void setUserSetting(String settingName, int value) {
         Settings.System.putIntForUser(
                 mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
new file mode 100644
index 0000000..1f163bd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.ContextWrapper;
+import android.hardware.vibrator.IVibrator;
+import android.os.IBinder;
+import android.os.IVibratorStateListener;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Tests for {@link VibratorController}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibratorControllerTest
+ */
+@Presubmit
+public class VibratorControllerTest {
+
+    @Rule public MockitoRule rule = MockitoJUnit.rule();
+    @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
+
+    @Mock private VibratorController.OnVibrationCompleteListener mOnCompleteListenerMock;
+    @Mock private VibratorController.NativeWrapper mNativeWrapperMock;
+    @Mock private IVibratorStateListener mVibratorStateListenerMock;
+    @Mock private IBinder mVibratorStateListenerBinderMock;
+
+    private TestLooper mTestLooper;
+    private ContextWrapper mContextSpy;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+
+        ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
+        when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
+        when(mVibratorStateListenerMock.asBinder()).thenReturn(mVibratorStateListenerBinderMock);
+    }
+
+    private VibratorController createController() {
+        return new VibratorController(/* vibratorId= */ 0, mOnCompleteListenerMock,
+                mNativeWrapperMock);
+    }
+
+    private VibratorController createController(int vibratorId) {
+        return new VibratorController(vibratorId, mOnCompleteListenerMock, mNativeWrapperMock);
+    }
+
+    @Test
+    public void createController_initializesNativeWrapper() {
+        int vibratorId = 13;
+        VibratorController controller = createController(vibratorId);
+        assertEquals(vibratorId, controller.getVibratorId());
+        verify(mNativeWrapperMock).init(eq(vibratorId), notNull());
+    }
+
+    @Test
+    public void isAvailable_withVibratorHalPresent_returnsTrue() {
+        when(mNativeWrapperMock.isAvailable()).thenReturn(true);
+        assertTrue(createController().isAvailable());
+    }
+
+    @Test
+    public void isAvailable_withNoVibratorHalPresent_returnsFalse() {
+        when(mNativeWrapperMock.isAvailable()).thenReturn(false);
+        assertFalse(createController().isAvailable());
+    }
+
+    @Test
+    public void hasCapability_withSupport_returnsTrue() {
+        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        assertTrue(createController().hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
+    }
+
+    @Test
+    public void hasCapability_withNoSupport_returnsFalse() {
+        assertFalse(createController().hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL));
+        assertFalse(createController().hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
+        assertFalse(createController().hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
+        assertFalse(createController().hasCapability(IVibrator.CAP_EXTERNAL_CONTROL));
+        assertFalse(createController().hasCapability(IVibrator.CAP_ON_CALLBACK));
+    }
+
+    @Test
+    public void areEffectsSupported_withNullResultFromNative_returnsSupportUnknown() {
+        when(mNativeWrapperMock.getSupportedEffects()).thenReturn(null);
+        assertArrayEquals(new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN},
+                createController().areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK}));
+    }
+
+    @Test
+    public void areEffectsSupported_withSomeEffectsSupported_returnsSupportYesAndNoForEffects() {
+        int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
+
+        when(mNativeWrapperMock.getSupportedEffects())
+                .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+        assertArrayEquals(
+                new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
+                        Vibrator.VIBRATION_EFFECT_SUPPORT_NO},
+                createController().areEffectsSupported(effects));
+    }
+
+    @Test
+    public void arePrimitivesSupported_withoutComposeCapability_returnsAlwaysFalse() {
+        assertArrayEquals(new boolean[]{false, false},
+                createController().arePrimitivesSupported(new int[]{
+                        VibrationEffect.Composition.PRIMITIVE_CLICK,
+                        VibrationEffect.Composition.PRIMITIVE_TICK
+                }));
+    }
+
+    @Test
+    public void arePrimitivesSupported_withNullResultFromNative_returnsAlwaysFalse() {
+        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        when(mNativeWrapperMock.getSupportedPrimitives()).thenReturn(null);
+
+        assertArrayEquals(new boolean[]{false, false},
+                createController().arePrimitivesSupported(new int[]{
+                        VibrationEffect.Composition.PRIMITIVE_CLICK,
+                        VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
+                }));
+    }
+
+    @Test
+    public void arePrimitivesSupported_withSomeSupportedPrimitives_returnsBasedOnNativeResult() {
+        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        when(mNativeWrapperMock.getSupportedPrimitives())
+                .thenReturn(new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
+
+        assertArrayEquals(new boolean[]{true, false},
+                createController().arePrimitivesSupported(new int[]{
+                        VibrationEffect.Composition.PRIMITIVE_CLICK,
+                        VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
+                }));
+    }
+
+    @Test
+    public void setExternalControl_withCapability_enablesExternalControl() {
+        mockVibratorCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+        VibratorController controller = createController();
+        assertFalse(controller.isUnderExternalControl());
+
+        controller.setExternalControl(true);
+        assertTrue(controller.isUnderExternalControl());
+
+        controller.setExternalControl(false);
+        assertFalse(controller.isUnderExternalControl());
+
+        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
+        inOrderVerifier.verify(mNativeWrapperMock).setExternalControl(eq(true));
+        inOrderVerifier.verify(mNativeWrapperMock).setExternalControl(eq(false));
+    }
+
+    @Test
+    public void setExternalControl_withNoCapability_ignoresExternalControl() {
+        VibratorController controller = createController();
+        assertFalse(controller.isUnderExternalControl());
+
+        controller.setExternalControl(true);
+        assertFalse(controller.isUnderExternalControl());
+
+        verify(mNativeWrapperMock, never()).setExternalControl(anyBoolean());
+    }
+
+    @Test
+    public void updateAlwaysOn_withCapability_enablesAlwaysOnEffect() {
+        mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        VibrationEffect.Prebaked effect = (VibrationEffect.Prebaked)
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+        createController().updateAlwaysOn(1, effect);
+
+        verify(mNativeWrapperMock).alwaysOnEnable(
+                eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
+                eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM));
+    }
+
+    @Test
+    public void updateAlwaysOn_withNullEffect_disablesAlwaysOnEffect() {
+        mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        createController().updateAlwaysOn(1, null);
+        verify(mNativeWrapperMock).alwaysOnDisable(eq(1L));
+    }
+
+    @Test
+    public void updateAlwaysOn_withoutCapability_ignoresEffect() {
+        VibrationEffect.Prebaked effect = (VibrationEffect.Prebaked)
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+        createController().updateAlwaysOn(1, effect);
+
+        verify(mNativeWrapperMock, never()).alwaysOnDisable(anyLong());
+        verify(mNativeWrapperMock, never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
+    }
+
+    @Test
+    public void on_withDuration_turnsVibratorOn() {
+        VibratorController controller = createController();
+        controller.on(100, 10);
+
+        assertTrue(controller.isVibrating());
+        verify(mNativeWrapperMock).on(eq(100L), eq(10L));
+    }
+
+    @Test
+    public void on_withPrebaked_performsEffect() {
+        when(mNativeWrapperMock.perform(anyLong(), anyLong(), anyLong())).thenReturn(10L);
+        VibratorController controller = createController();
+
+        VibrationEffect.Prebaked effect = (VibrationEffect.Prebaked)
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+        controller.on(effect, 11);
+
+        assertTrue(controller.isVibrating());
+        verify(mNativeWrapperMock).perform(eq((long) VibrationEffect.EFFECT_CLICK),
+                eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), eq(11L));
+    }
+
+    @Test
+    public void on_withComposed_performsEffect() {
+        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        VibratorController controller = createController();
+
+        VibrationEffect.Composed effect = (VibrationEffect.Composed)
+                VibrationEffect.startComposition()
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
+                        .compose();
+        controller.on(effect, 12);
+
+        ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
+                ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
+
+        assertTrue(controller.isVibrating());
+        verify(mNativeWrapperMock).compose(primitivesCaptor.capture(), eq(12L));
+
+        // Check all primitive effect fields are passed down to the HAL.
+        assertEquals(1, primitivesCaptor.getValue().length);
+        VibrationEffect.Composition.PrimitiveEffect primitive = primitivesCaptor.getValue()[0];
+        assertEquals(VibrationEffect.Composition.PRIMITIVE_CLICK, primitive.id);
+        assertEquals(0.5f, primitive.scale, /* delta= */ 1e-2);
+        assertEquals(10, primitive.delay);
+    }
+
+    @Test
+    public void off_turnsOffVibrator() {
+        VibratorController controller = createController();
+        controller.on(100, 1);
+        assertTrue(controller.isVibrating());
+
+        controller.off();
+        controller.off();
+        assertFalse(controller.isVibrating());
+        verify(mNativeWrapperMock, times(2)).off();
+    }
+
+    @Test
+    public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
+        VibratorController controller = createController();
+
+        controller.registerVibratorStateListener(mVibratorStateListenerMock);
+        controller.on(10, 1);
+        controller.on(100, 2);
+        controller.off();
+        controller.off();
+
+        InOrder inOrderVerifier = inOrder(mVibratorStateListenerMock);
+        // First notification done when listener is registered.
+        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(false);
+        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(true));
+        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(false));
+        inOrderVerifier.verifyNoMoreInteractions();
+    }
+
+    @Test
+    public void unregisterVibratorStateListener_callbackNotTriggeredAfter() throws Exception {
+        VibratorController controller = createController();
+
+        controller.registerVibratorStateListener(mVibratorStateListenerMock);
+        verify(mVibratorStateListenerMock).onVibrating(false);
+
+        controller.on(10, 1);
+        verify(mVibratorStateListenerMock).onVibrating(true);
+
+        controller.unregisterVibratorStateListener(mVibratorStateListenerMock);
+        Mockito.clearInvocations(mVibratorStateListenerMock);
+
+        controller.on(10, 1);
+        verifyNoMoreInteractions(mVibratorStateListenerMock);
+    }
+
+    private void mockVibratorCapabilities(int capabilities) {
+        when(mNativeWrapperMock.getCapabilities()).thenReturn((long) capabilities);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
similarity index 92%
rename from services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java
rename to services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
index 2904a5b..a67f645 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.utils;
+package com.android.server.testutils;
 
 import android.annotation.NonNull;
 import android.provider.DeviceConfig;
@@ -22,6 +22,7 @@
 import android.util.Pair;
 
 import com.android.internal.util.Preconditions;
+import com.android.server.utils.DeviceConfigInterface;
 
 import java.lang.reflect.Constructor;
 import java.util.HashMap;
@@ -122,6 +123,19 @@
     }
 
     @Override
+    public float getFloat(String namespace, String name, float defaultValue) {
+        String value = getProperty(namespace, name);
+        if (value == null) {
+            return defaultValue;
+        }
+        try {
+            return Float.parseFloat(value);
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
+    @Override
     public boolean getBoolean(String namespace, String name, boolean defaultValue) {
         String value = getProperty(namespace, name);
         return value != null ? Boolean.parseBoolean(value) : defaultValue;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index c507928..4a4d9bc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -54,6 +54,8 @@
 import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
@@ -267,7 +269,7 @@
                     mIpm, approvalLevel);
 
             // approved services aren't in xml
-            XmlPullParser parser = Xml.newPullParser();
+            TypedXmlPullParser parser = Xml.newFastPullParser();
             parser.setInput(new BufferedInputStream(new ByteArrayInputStream(new byte[]{})),
                     null);
             writeExpectedValuesToSettings(approvalLevel);
@@ -335,7 +337,7 @@
             String testComponent = "user.test.component/C1";
             String resolvedValue =
                     (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent : testPackage;
-            XmlPullParser parser =
+            TypedXmlPullParser parser =
                     getParserWithEntries(service, getXmlEntry(resolvedValue, 0, true));
 
             service.readXml(parser, null, true, 10);
@@ -357,7 +359,7 @@
             String resolvedValue =
                     (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent : testPackage;
             String xmlEntry = getXmlEntry(resolvedValue, 0, true, false);
-            XmlPullParser parser = getParserWithEntries(service, xmlEntry);
+            TypedXmlPullParser parser = getParserWithEntries(service, xmlEntry);
 
             service.readXml(parser, null, true, 0);
 
@@ -384,7 +386,7 @@
         ManagedServices service2 =
                 new TestManagedServices(
                         getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         BufferedOutputStream outStream = new BufferedOutputStream(baos);
         serializer.setOutput(outStream, "utf-8");
@@ -396,7 +398,7 @@
         serializer.endDocument();
         outStream.flush();
 
-        final XmlPullParser parser = Xml.newPullParser();
+        final TypedXmlPullParser parser = Xml.newFastPullParser();
         BufferedInputStream input = new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray()));
 
@@ -536,7 +538,7 @@
                     service,
                     Collections.singletonList(service.getPackageName(resolvedValue10)),
                     10);
-            XmlPullParser parser =
+            TypedXmlPullParser parser =
                     getParserWithEntries(
                             service,
                             getXmlEntry(resolvedValue0, 0, true),
@@ -544,7 +546,7 @@
             service.readXml(parser, null, false, UserHandle.USER_ALL);
 
             // Write backup.
-            XmlSerializer serializer = new FastXmlSerializer();
+            TypedXmlSerializer serializer = Xml.newFastSerializer();
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
             serializer.startDocument(null, true);
@@ -557,7 +559,7 @@
             service.setPackageOrComponentEnabled(resolvedValue10, 10, true, false);
 
             // Parse backup via restore.
-            XmlPullParser restoreParser = Xml.newPullParser();
+            TypedXmlPullParser restoreParser = Xml.newFastPullParser();
             restoreParser.setInput(
                     new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
             restoreParser.nextTag();
@@ -608,7 +610,7 @@
                 addExpectedServices(service, entriesExpectedToHaveServices, userInfo.id);
             }
 
-            XmlSerializer serializer = new FastXmlSerializer();
+            TypedXmlSerializer serializer = Xml.newFastSerializer();
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
             serializer.startDocument(null, true);
@@ -618,7 +620,7 @@
             serializer.endDocument();
             serializer.flush();
 
-            XmlPullParser parser = Xml.newPullParser();
+            TypedXmlPullParser parser = Xml.newFastPullParser();
             parser.setInput(new BufferedInputStream(
                     new ByteArrayInputStream(baos.toByteArray())), null);
             parser.nextTag();
@@ -640,7 +642,7 @@
                     mIpm, approvalLevel);
             loadXml(service);
 
-            XmlSerializer serializer = new FastXmlSerializer();
+            TypedXmlSerializer serializer = Xml.newFastSerializer();
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
             serializer.startDocument(null, true);
@@ -666,7 +668,7 @@
                     mIpm, approvalLevel);
             loadXml(service);
 
-            XmlSerializer serializer = new FastXmlSerializer();
+            TypedXmlSerializer serializer = Xml.newFastSerializer();
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
             serializer.startDocument(null, true);
@@ -674,7 +676,7 @@
             serializer.endDocument();
             serializer.flush();
 
-            XmlPullParser parser = Xml.newPullParser();
+            TypedXmlPullParser parser = Xml.newFastPullParser();
             byte[] rawOutput = baos.toByteArray();
             parser.setInput(new BufferedInputStream(
                     new ByteArrayInputStream(rawOutput)), null);
@@ -1387,7 +1389,7 @@
 
     private void loadXml(ManagedServices service) throws Exception {
         String xmlString = createXml(service);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xmlString.getBytes())), null);
         parser.nextTag();
@@ -1423,7 +1425,7 @@
         return xml.toString();
     }
 
-    private XmlPullParser getParserWithEntries(ManagedServices service, String... xmlEntries)
+    private TypedXmlPullParser getParserWithEntries(ManagedServices service, String... xmlEntries)
             throws Exception {
         final StringBuffer xml = new StringBuffer();
         xml.append("<" + service.getConfig().xmlTag + ">\n");
@@ -1432,7 +1434,7 @@
         }
         xml.append("</" + service.getConfig().xmlTag + ">");
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.toString().getBytes())), null);
         parser.nextTag();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index f649911..8c2038b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -36,6 +36,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.IntArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.server.UiServiceTestCase;
@@ -126,7 +128,7 @@
                 + "<service_listing approved=\"b/b\" user=\"10\" primary=\"true\" />"
                 + "</enabled_assistants>";
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.toString().getBytes())), null);
         parser.nextTag();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 09a4289..6083237 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -160,6 +160,8 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.widget.RemoteViews;
 
@@ -3446,7 +3448,7 @@
                 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
                 false,
                 UserHandle.USER_ALL);
-        verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class), anyLong());
+        verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong());
     }
 
     @Test
@@ -3887,12 +3889,12 @@
         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
         channel.setSound(Uri.EMPTY, null);
 
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         channel.writeXmlForBackup(serializer, getContext());
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
@@ -3915,7 +3917,7 @@
         NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
         channel.setVibrationPattern(new long[0]);
 
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         channel.writeXml(serializer);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 7ec8689..98c4a2d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -99,6 +99,8 @@
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.InstrumentationRegistry;
@@ -280,7 +282,7 @@
     private ByteArrayOutputStream writeXmlAndPurge(
             String pkg, int uid, boolean forBackup, int userId, String... channelIds)
             throws Exception {
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
@@ -300,7 +302,7 @@
 
     private void loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)
             throws Exception {
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null);
         parser.nextTag();
         mHelper.readXml(parser, forRestore, userId);
@@ -717,7 +719,7 @@
         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
                 UID_N_MR1});
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
                 null);
         parser.nextTag();
@@ -772,7 +774,7 @@
                 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" visibility=\""
                 + Notification.VISIBILITY_PRIVATE + "\" />\n"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
                 null);
         parser.nextTag();
@@ -2559,7 +2561,7 @@
                 + " importance=\"3\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -2580,7 +2582,7 @@
                 + " importance=\"3\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -2612,7 +2614,7 @@
                 + " importance=\"3\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -2753,7 +2755,7 @@
                 + "<channel id=\"b\" name=\"b\" importance=\"3\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -2779,7 +2781,7 @@
                 + "<channel id=\"c\" name=\"c\" importance=\"3\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -3047,7 +3049,7 @@
         toAdd.add(new Pair(PKG_O, UID_O));
         mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
                 null);
         parser.nextTag();
@@ -3121,7 +3123,7 @@
                 + "<channel id=\"" + extraChannel1 + "\" name=\"hi\" importance=\"3\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -3154,12 +3156,12 @@
                 + "</ranking>";
 
         // trigger a restore for both users
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())),
                 null);
         parser.nextTag();
         mHelper.readXml(parser, true, 0);
-        parser = Xml.newPullParser();
+        parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())),
                 null);
         parser.nextTag();
@@ -3242,7 +3244,7 @@
                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -3261,7 +3263,7 @@
                 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"other\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
@@ -3280,7 +3282,7 @@
                 + "<channel id=\"id\" name=\"hi\" importance=\"3\"/>"
                 + "</package>"
                 + "</ranking>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
                 null);
         parser.nextTag();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 3deeea2..35b224a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -43,6 +43,8 @@
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.IntArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -95,7 +97,7 @@
                 + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
                 + "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
                 + "</snoozed-notifications>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml_string.getBytes())), null);
         mSnoozeHelper.readXml(parser, 1);
@@ -114,12 +116,12 @@
                 + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
                 + "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
                 + "</snoozed-notifications>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml_string.getBytes())), null);
         mSnoozeHelper.readXml(parser, 1);
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
         mSnoozeHelper.writeXml(serializer);
@@ -137,7 +139,7 @@
                 + "<context version=\"1\" user-id=\"0\" notification=\"notification\" "
                 + "pkg=\"pkg\" key=\"key2\" id=\"uri\"/>"
                 + "</snoozed-notifications>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml_string.getBytes())), null);
         mSnoozeHelper.readXml(parser, 1);
@@ -151,7 +153,7 @@
             throws XmlPullParserException, IOException {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 999999999);
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
@@ -159,7 +161,7 @@
         serializer.endDocument();
         serializer.flush();
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), "utf-8");
         mSnoozeHelper.readXml(parser, 1);
@@ -175,7 +177,7 @@
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 0);
        // Thread.sleep(100);
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
@@ -183,7 +185,7 @@
         serializer.endDocument();
         serializer.flush();
         Thread.sleep(10);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), "utf-8");
         mSnoozeHelper.readXml(parser, 2);
@@ -227,7 +229,7 @@
                 + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
                 + "pkg=\"pkg\" key=\"key2\" time=\"" + 15+ "\"/>"
                 + "</snoozed-notifications>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml_string.getBytes())), null);
         mSnoozeHelper.readXml(parser, 4);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 013a994..5262465 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -30,6 +30,8 @@
 import android.service.notification.ZenModeConfig.EventInfo;
 import android.service.notification.ZenPolicy;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -199,7 +201,7 @@
         rule.name = "name";
         rule.snoozing = true;
 
-        XmlSerializer out = new FastXmlSerializer();
+        TypedXmlSerializer out = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         out.setOutput(new BufferedOutputStream(baos), "utf-8");
         out.startDocument(null, true);
@@ -208,7 +210,7 @@
         out.endTag(null, tag);
         out.endDocument();
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 3430dbd..cfdd246 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -95,6 +95,8 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.R;
@@ -189,14 +191,14 @@
                 + "&amp;end=7.0&amp;exitAtAlarm=true\"/>"
                 + "<disallow visualEffects=\"511\" />"
                 + "</zen>";
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
         return new XmlResourceParserImpl(parser);
     }
 
     private ByteArrayOutputStream writeXmlAndPurge(Integer version) throws Exception {
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
@@ -209,7 +211,7 @@
 
     private ByteArrayOutputStream writeXmlAndPurgeForUser(Integer version, int userId)
             throws Exception {
-        XmlSerializer serializer = new FastXmlSerializer();
+        TypedXmlSerializer serializer = Xml.newFastSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
@@ -222,8 +224,8 @@
         return baos;
     }
 
-    private XmlPullParser getParserForByteStream(ByteArrayOutputStream baos) throws Exception {
-        XmlPullParser parser = Xml.newPullParser();
+    private TypedXmlPullParser getParserForByteStream(ByteArrayOutputStream baos) throws Exception {
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(
                 new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
@@ -837,7 +839,7 @@
         ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
 
         ByteArrayOutputStream baos = writeXmlAndPurge(null);
-        XmlPullParser parser = getParserForByteStream(baos);
+        TypedXmlPullParser parser = getParserForByteStream(baos);
         mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals("Config mismatch: current vs expected: "
@@ -962,7 +964,7 @@
         mZenModeHelperSpy.mConfigs.put(11, newConfig11);
 
         // Parse backup data.
-        XmlPullParser parser = getParserForByteStream(baos);
+        TypedXmlPullParser parser = getParserForByteStream(baos);
         mZenModeHelperSpy.readXml(parser, true, 10);
         mZenModeHelperSpy.readXml(parser, true, 11);
 
@@ -980,7 +982,7 @@
         ZenModeConfig original = mZenModeHelperSpy.mConfig.copy();
 
         ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
-        XmlPullParser parser = getParserForByteStream(baos);
+        TypedXmlPullParser parser = getParserForByteStream(baos);
         mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM);
 
         assertEquals("Config mismatch: current vs original: "
@@ -1000,7 +1002,7 @@
         ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
 
         // Restore data for user 10.
-        XmlPullParser parser = getParserForByteStream(baos);
+        TypedXmlPullParser parser = getParserForByteStream(baos);
         mZenModeHelperSpy.readXml(parser, true, 10);
 
         ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10);
@@ -1045,7 +1047,7 @@
         ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
 
         ByteArrayOutputStream baos = writeXmlAndPurge(null);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
@@ -1086,7 +1088,7 @@
         ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
 
         ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
-        XmlPullParser parser = getParserForByteStream(baos);
+        TypedXmlPullParser parser = getParserForByteStream(baos);
         mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM);
 
         ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId);
@@ -1113,7 +1115,7 @@
 
         // set previous version
         ByteArrayOutputStream baos = writeXmlAndPurge(5);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
@@ -1133,7 +1135,7 @@
                 + "<disallow visualEffects=\"511\" />"
                 + "</zen>";
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
@@ -1149,7 +1151,7 @@
                 + "<disallow visualEffects=\"511\" />"
                 + "</zen>";
 
-        parser = Xml.newPullParser();
+        parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
@@ -1168,7 +1170,7 @@
                 + "<disallow visualEffects=\"511\" />"
                 + "</zen>";
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
@@ -1187,7 +1189,7 @@
                 + "<disallow visualEffects=\"511\" />"
                 + "</zen>";
 
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
@@ -1206,7 +1208,7 @@
                 + "<disallow visualEffects=\"511\" />"
                 + "</zen>";
 
-        parser = Xml.newPullParser();
+        parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
@@ -1222,7 +1224,7 @@
                 + "<disallow visualEffects=\"511\" />"
                 + "</zen>";
 
-        parser = Xml.newPullParser();
+        parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
@@ -1242,7 +1244,7 @@
 
         // set previous version
         ByteArrayOutputStream baos = writeXmlAndPurge(5);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
@@ -1278,7 +1280,7 @@
 
         // set previous version
         ByteArrayOutputStream baos = writeXmlAndPurge(5);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
@@ -1330,7 +1332,7 @@
 
         // set previous version
         ByteArrayOutputStream baos = writeXmlAndPurge(5);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
@@ -1399,7 +1401,7 @@
 
         // set previous version
         ByteArrayOutputStream baos = writeXmlAndPurge(5);
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
@@ -1628,12 +1630,12 @@
     }
 
     /**
-     * Wrapper to use XmlPullParser as XmlResourceParser for Resources.getXml()
+     * Wrapper to use TypedXmlPullParser as XmlResourceParser for Resources.getXml()
      */
     final class XmlResourceParserImpl implements XmlResourceParser {
-        private XmlPullParser parser;
+        private TypedXmlPullParser parser;
 
-        public XmlResourceParserImpl(XmlPullParser parser) {
+        public XmlResourceParserImpl(TypedXmlPullParser parser) {
             this.parser = parser;
         }
 
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 7f4f3dd..0ed037c 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -65,8 +65,6 @@
                   android:turnScreenOn="true" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ResumeWhilePausingActivity"
                   android:resumeWhilePausing="true"/>
-        <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
-                  android:showWhenLocked="true" android:allowEmbedded="true"/>
         <activity android:name="com.android.server.wm.ActivityLeakTests$DetectLeakActivity" />
     </application>
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 53ade0e..2304efc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -71,6 +71,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
 
@@ -376,6 +377,27 @@
     }
 
     @Test
+    public void testDestroyedActivityNotScheduleConfigChanged() throws RemoteException {
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setCreateTask(true)
+                .setConfigChanges(CONFIG_ORIENTATION)
+                .build();
+        final Task task = activity.getTask();
+        activity.setState(DESTROYED, "Testing");
+
+        final Configuration newConfig = new Configuration(task.getConfiguration());
+        newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+                ? ORIENTATION_LANDSCAPE
+                : ORIENTATION_PORTRAIT;
+        task.onRequestedOverrideConfigurationChanged(newConfig);
+
+        ensureActivityConfiguration(activity);
+
+        verify(mAtm.getLifecycleManager(), never())
+                .scheduleTransaction(any(), any(), isA(ActivityConfigurationChangeItem.class));
+    }
+
+    @Test
     public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
@@ -401,7 +423,7 @@
 
         // Mimic the behavior that display doesn't handle app's requested orientation.
         final DisplayContent dc = activity.getTask().getDisplayContent();
-        doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
+        doReturn(false).when(dc).onDescendantOrientationChanged(any());
         doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
 
         final int requestedOrientation;
@@ -1658,7 +1680,7 @@
         final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
                 ? SCREEN_ORIENTATION_LANDSCAPE
                 : SCREEN_ORIENTATION_PORTRAIT;
-        doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
+        doReturn(false).when(r).onDescendantOrientationChanged(any());
         r.setOrientation(rotatedOrentation);
     }
 
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 bded3f9..565bf8b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -422,7 +422,7 @@
         // verify that values are passed to the modifier. Values are passed thrice -- two for
         // setting initial state, another when task is created.
         verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
-                anyInt(), any(), any());
+                anyInt(), any(), any(), any());
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 017ed88..475e462 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -34,6 +34,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.timeout;
 
 import android.app.WaitResult;
 import android.content.pm.ActivityInfo;
@@ -45,6 +46,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests for the {@link ActivityTaskSupervisor} class.
  *
@@ -190,4 +193,16 @@
 
         assertThat(allowedOnUntrusted).isFalse();
     }
+
+    /**
+     * We need to launch home again after user unlocked for those displays that do not have
+     * encryption aware home app.
+     */
+    @Test
+    public void testStartHomeAfterUserUnlocked() {
+        mSupervisor.onUserUnlocked(0);
+        waitHandlerIdle(mAtm.mH);
+        verify(mRootWindowContainer, timeout(TimeUnit.SECONDS.toMillis(10)))
+                .startHomeOnEmptyDisplays("userUnlocked");
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 6ca69bf..8cc515e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -196,7 +196,7 @@
     @Test
     public void testCancelRemoteAnimationWhenFreeze() {
         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
-        doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
+        doReturn(false).when(dc).onDescendantOrientationChanged(any());
         final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
                 dc, "exiting app");
         final ActivityRecord exitingActivity= exitingAppWindow.mActivityRecord;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
index 5828d02..59b12e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
@@ -366,6 +366,30 @@
         assertTrue(child.getConfiguration().windowConfiguration.getMaxBounds().isEmpty());
     }
 
+    @Test
+    public void testOnRequestedOverrideConfigurationChangedOverrideMaxBounds() {
+        final TestConfigurationContainer root =
+                new TestConfigurationContainer(true /* providesMaxBounds */);
+        final Rect bounds = new Rect(0, 0, 10, 10);
+        final TestConfigurationContainer child = new TestConfigurationContainer();
+        root.addChild(child);
+        final Configuration configuration = new Configuration();
+        configuration.windowConfiguration.setBounds(bounds);
+
+        root.onRequestedOverrideConfigurationChanged(configuration);
+
+        assertEquals(bounds, root.getBounds());
+        assertEquals(bounds, root.getConfiguration().windowConfiguration.getBounds());
+        assertEquals(bounds, child.getBounds());
+        assertEquals(bounds, child.getConfiguration().windowConfiguration.getBounds());
+
+        assertEquals(bounds, root.getMaxBounds());
+        assertEquals(bounds, root.getConfiguration().windowConfiguration.getMaxBounds());
+        assertEquals(bounds, child.getMaxBounds());
+        assertEquals(bounds, child.getConfiguration().windowConfiguration.getMaxBounds());
+    }
+
+
     /**
      * Contains minimal implementation of {@link ConfigurationContainer}'s abstract behavior needed
      * for testing.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
index 06a6882..bc91c70 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -87,7 +87,7 @@
         final Task task = new TaskBuilder(mSupervisor)
                 .setTaskDisplayArea(mTaskDisplayArea).setCreateActivity(true).build();
         final ActivityRecord activity = task.getTopNonFinishingActivity();
-        doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any(), any());
+        doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any());
         activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
 
         // Display is portrait, DisplayAreaGroup inherits that
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
index 3220d1d..1198ee2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
@@ -16,8 +16,13 @@
 
 package com.android.server.wm;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
+import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -25,6 +30,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -55,9 +61,12 @@
 public class DisplayAreaOrganizerTest extends WindowTestsBase {
 
     private DisplayArea mTestDisplayArea;
+    private DisplayAreaOrganizerController mOrganizerController;
 
     @Before
     public void setUp() {
+        mOrganizerController =
+                mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
         WindowContainer parentWindow = mDisplayContent.getDefaultTaskDisplayArea().getParent();
         mTestDisplayArea = new DisplayArea(mWm, DisplayArea.Type.ANY,
                 "TestDisplayArea", FEATURE_VENDOR_FIRST);
@@ -76,8 +85,7 @@
 
     private IDisplayAreaOrganizer registerMockOrganizer(int feature, Binder binder) {
         final IDisplayAreaOrganizer organizer = createMockOrganizer(binder);
-        mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController
-                .registerOrganizer(organizer, feature);
+        mOrganizerController.registerOrganizer(organizer, feature);
         return organizer;
     }
 
@@ -87,16 +95,10 @@
         return organizer;
     }
 
-    private void unregisterMockOrganizer(IDisplayAreaOrganizer organizer) {
-        mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController
-                .unregisterOrganizer(organizer);
-    }
-
     @Test
     public void testRegisterOrganizer() throws RemoteException {
-        IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
-        List<DisplayAreaAppearedInfo> infos = mWm.mAtmService.mWindowOrganizerController
-                .mDisplayAreaOrganizerController
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+        List<DisplayAreaAppearedInfo> infos = mOrganizerController
                 .registerOrganizer(organizer, FEATURE_VENDOR_FIRST).getList();
 
         // Return a list contains the DA, and no onDisplayAreaAppeared triggered.
@@ -108,16 +110,135 @@
     }
 
     @Test
+    public void testRegisterOrganizer_alreadyRegisteredFeature() {
+        registerMockOrganizer(FEATURE_VENDOR_FIRST);
+        assertThrows(IllegalStateException.class,
+                () -> registerMockOrganizer(FEATURE_VENDOR_FIRST));
+    }
+
+    @Test
+    public void testCreateTaskDisplayArea() {
+        final String newTdaName = "testTda";
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+        final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+                organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+
+        final int newTdaIndex =
+                mTestDisplayArea.getParent().mChildren.indexOf(mTestDisplayArea) + 1;
+        final WindowContainer wc = mTestDisplayArea.getParent().getChildAt(newTdaIndex);
+
+        // A new TaskDisplayArea is created on the top.
+        assertThat(wc).isInstanceOf(TaskDisplayArea.class);
+        assertThat(tdaInfo.getDisplayAreaInfo().displayId).isEqualTo(DEFAULT_DISPLAY);
+        assertThat(tdaInfo.getDisplayAreaInfo().token)
+                .isEqualTo(wc.mRemoteToken.toWindowContainerToken());
+
+        final TaskDisplayArea tda = wc.asTaskDisplayArea();
+
+        assertThat(tda.getName()).isEqualTo(newTdaName);
+        assertThat(tda.mFeatureId).isEqualTo(tdaInfo.getDisplayAreaInfo().featureId);
+        assertThat(tda.mCreatedByOrganizer).isTrue();
+        assertThat(tda.mOrganizer).isEqualTo(organizer);
+    }
+
+    @Test
+    public void testCreateTaskDisplayArea_incrementalTdaFeatureId() {
+        final String newTdaName = "testTda";
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+        final DisplayAreaAppearedInfo tdaInfo1 = mOrganizerController.createTaskDisplayArea(
+                organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+        final DisplayAreaAppearedInfo tdaInfo2 = mOrganizerController.createTaskDisplayArea(
+                organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+
+        // New created TDA has unique feature id starting from FEATURE_RUNTIME_TASK_CONTAINER_FIRST.
+        assertThat(tdaInfo1.getDisplayAreaInfo().featureId).isEqualTo(
+                FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+        assertThat(tdaInfo2.getDisplayAreaInfo().featureId).isEqualTo(
+                FEATURE_RUNTIME_TASK_CONTAINER_FIRST + 1);
+    }
+
+
+    @Test
+    public void testCreateTaskDisplayArea_invalidDisplayAndRoot() {
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+        assertThrows(IllegalArgumentException.class, () ->
+                mOrganizerController.createTaskDisplayArea(
+                        organizer, SystemServicesTestRule.sNextDisplayId + 1, FEATURE_ROOT,
+                        "testTda"));
+        assertThrows(IllegalArgumentException.class, () ->
+                mOrganizerController.createTaskDisplayArea(
+                        organizer, DEFAULT_DISPLAY, FEATURE_ROOT - 1, "testTda"));
+    }
+
+    @Test
+    public void testDeleteTaskDisplayArea() {
+        final String newTdaName = "testTda";
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+        final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+                organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+        final int tdaFeatureId = tdaInfo.getDisplayAreaInfo().featureId;
+
+        final TaskDisplayArea newTda = mDisplayContent.getItemFromDisplayAreas(
+                da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+        spyOn(newTda);
+
+        mOrganizerController.deleteTaskDisplayArea(newTda.mRemoteToken.toWindowContainerToken());
+
+        verify(newTda).remove();
+        verify(newTda).removeImmediately();
+        assertThat(newTda.mOrganizer).isNull();
+        assertThat(newTda.isRemoved()).isTrue();
+
+        final TaskDisplayArea curTda = mDisplayContent.getItemFromDisplayAreas(
+                da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+
+        assertThat(curTda).isNull();
+    }
+
+    @Test
+    public void testUnregisterOrganizer_deleteNewCreatedTaskDisplayArea() {
+        final String newTdaName = "testTda";
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+        final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+                organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
+        final int tdaFeatureId = tdaInfo.getDisplayAreaInfo().featureId;
+
+        final TaskDisplayArea newTda = mDisplayContent.getItemFromDisplayAreas(
+                da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+        spyOn(newTda);
+
+        mOrganizerController.unregisterOrganizer(organizer);
+
+        verify(newTda).remove();
+        verify(newTda).removeImmediately();
+        assertThat(newTda.mOrganizer).isNull();
+        assertThat(newTda.isRemoved()).isTrue();
+
+        final TaskDisplayArea curTda = mDisplayContent.getItemFromDisplayAreas(
+                da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
+
+        assertThat(curTda).isNull();
+    }
+
+    @Test
+    public void testDeleteTaskDisplayArea_invalidTaskDisplayArea() {
+        final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
+        assertThrows(IllegalArgumentException.class, () ->
+                mOrganizerController.deleteTaskDisplayArea(
+                        tda.mRemoteToken.toWindowContainerToken()));
+    }
+
+    @Test
     public void testAppearedVanished() throws RemoteException {
-        IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
-        unregisterMockOrganizer(organizer);
+        final IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
+        mOrganizerController.unregisterOrganizer(organizer);
 
         verify(organizer).onDisplayAreaVanished(any());
     }
 
     @Test
     public void testChanged() throws RemoteException {
-        IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
+        final IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
         mDisplayContent.setBounds(new Rect(0, 0, 1000, 1000));
 
         verify(organizer).onDisplayAreaInfoChanged(any());
@@ -137,7 +258,7 @@
 
         assertThat(mTestDisplayArea.mOrganizer).isNotNull();
 
-        unregisterMockOrganizer(createMockOrganizer(binder));
+        mOrganizerController.unregisterOrganizer(createMockOrganizer(binder));
 
         assertThat(mTestDisplayArea.mOrganizer).isNull();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 59b2d4f..025c5a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -468,14 +468,14 @@
 
         activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
-        verify(tda).onDescendantOrientationChanged(any(), any());
-        verify(mDisplayContent, never()).onDescendantOrientationChanged(any(), any());
+        verify(tda).onDescendantOrientationChanged(any());
+        verify(mDisplayContent, never()).onDescendantOrientationChanged(any());
 
         tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
         activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
 
-        verify(tda, times(2)).onDescendantOrientationChanged(any(), any());
-        verify(mDisplayContent).onDescendantOrientationChanged(any(), any());
+        verify(tda, times(2)).onDescendantOrientationChanged(any());
+        verify(mDisplayContent).onDescendantOrientationChanged(any());
     }
 
     private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index d921718..64065e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1202,6 +1202,17 @@
         assertTrue(mNavBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
                 ANIMATION_TYPE_FIXED_TRANSFORM));
 
+        // If the visibility of insets state is changed, the rotated state should be updated too.
+        final InsetsState rotatedState = app.getFixedRotationTransformInsetsState();
+        final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
+        assertEquals(state.getSource(ITYPE_STATUS_BAR).isVisible(),
+                rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
+        state.getSource(ITYPE_STATUS_BAR).setVisible(
+                !rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
+        mDisplayContent.getInsetsStateController().notifyInsetsChanged();
+        assertEquals(state.getSource(ITYPE_STATUS_BAR).isVisible(),
+                rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
+
         final Rect outFrame = new Rect();
         final Rect outInsets = new Rect();
         final Rect outStableInsets = new Rect();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 21bdc9e..79b2da1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -236,8 +236,7 @@
         final WindowState activity = createBaseApplicationWindow();
         activity.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
 
-        policy.adjustWindowParamsLw(activity, activity.mAttrs, 0 /* callingPid */,
-                0 /* callingUid */);
+        policy.adjustWindowParamsLw(activity, activity.mAttrs);
     }
 
     private WindowState createApplicationWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 94ffcda..20775e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -107,11 +107,9 @@
     }
 
     void addWindow(WindowState win) {
-        final int callingPid = Binder.getCallingPid();
-        final int callingUid = Binder.getCallingUid();
-        mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
-        assertEquals(WindowManagerGlobal.ADD_OKAY,
-                mDisplayPolicy.validateAddingWindowLw(win.mAttrs, callingPid, callingUid));
+        mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs);
+        assertEquals(WindowManagerGlobal.ADD_OKAY, mDisplayPolicy.validateAddingWindowLw(
+                win.mAttrs, Binder.getCallingPid(), Binder.getCallingUid()));
         mDisplayPolicy.addWindowLw(win, win.mAttrs);
         win.mHasSurface = true;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index b346bb8..554160c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
@@ -26,6 +27,8 @@
 
 import android.annotation.Nullable;
 import android.platform.test.annotations.Presubmit;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.view.Display;
 import android.view.DisplayAddress;
@@ -167,7 +170,7 @@
                 mBaseSettingsStorage, mOverrideSettingsStorage);
         SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
         overrideSettings.mShouldShowSystemDecors = true;
-        overrideSettings.mShouldShowIme = true;
+        overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
         provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
         assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
 
@@ -176,8 +179,8 @@
                 getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
         assertEquals("Attribute value must be stored", "true",
                 getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
-        assertEquals("Attribute value must be stored", "true",
-                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+        assertEquals("Attribute value must be stored", "0",
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "imePolicy"));
     }
 
     @Test
@@ -195,7 +198,7 @@
                 mBaseSettingsStorage, mOverrideSettingsStorage);
         SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
         overrideSettings.mShouldShowSystemDecors = true;
-        overrideSettings.mShouldShowIme = true;
+        overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
         provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
         assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
 
@@ -204,8 +207,8 @@
                 getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
         assertEquals("Attribute value must be stored", "true",
                 getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
-        assertEquals("Attribute value must be stored", "true",
-                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+        assertEquals("Attribute value must be stored", "0",
+                getStoredDisplayAttributeValue(mOverrideSettingsStorage, "imePolicy"));
     }
 
     /**
@@ -244,7 +247,7 @@
     private String getStoredDisplayAttributeValue(TestStorage storage, String attr)
             throws Exception {
         try (InputStream stream = storage.openRead()) {
-            XmlPullParser parser = Xml.newPullParser();
+            TypedXmlPullParser parser = Xml.newFastPullParser();
             parser.setInput(stream, StandardCharsets.UTF_8.name());
             int type;
             while ((type = parser.next()) != XmlPullParser.START_TAG
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 2ca5583..9e4cd16 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -22,6 +22,8 @@
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -49,7 +51,6 @@
 
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -319,17 +320,21 @@
     }
 
     @Test
-    public void testPrimaryDisplayShouldShowIme() {
-        assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
+    public void testPrimaryDisplayImePolicy() {
+        assertEquals(DISPLAY_IME_POLICY_LOCAL,
+                mDisplayWindowSettings.getImePolicyLocked(mPrimaryDisplay));
 
-        mDisplayWindowSettings.setShouldShowImeLocked(mPrimaryDisplay, false);
+        mDisplayWindowSettings.setDisplayImePolicy(mPrimaryDisplay,
+                DISPLAY_IME_POLICY_FALLBACK_DISPLAY);
 
-        assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
+        assertEquals(DISPLAY_IME_POLICY_LOCAL,
+                mDisplayWindowSettings.getImePolicyLocked(mPrimaryDisplay));
     }
 
     @Test
-    public void testSecondaryDisplayDefaultToNotShowIme() {
-        assertFalse(mDisplayWindowSettings.shouldShowImeLocked(mSecondaryDisplay));
+    public void testSecondaryDisplayDefaultToShowImeOnFallbackDisplay() {
+        assertEquals(DISPLAY_IME_POLICY_FALLBACK_DISPLAY,
+                mDisplayWindowSettings.getImePolicyLocked(mSecondaryDisplay));
     }
 
     @Test
@@ -400,17 +405,18 @@
     }
 
     @Test
-    public void testShouldShowImeWithinForceDesktopMode() {
+    public void testShouldShowImeOnDisplayWithinForceDesktopMode() {
         try {
             // Presume display enabled force desktop mode from developer options.
             final DisplayContent dc = createMockSimulatedDisplay();
             mWm.setForceDesktopModeOnExternalDisplays(true);
             final WindowManagerInternal wmInternal = LocalServices.getService(
                     WindowManagerInternal.class);
-            // Make sure WindowManagerInter#shouldShowIme as true is due to
-            // mForceDesktopModeOnExternalDisplays as true.
-            assertFalse(mWm.mDisplayWindowSettings.shouldShowImeLocked(dc));
-            assertTrue(wmInternal.shouldShowIme(dc.getDisplayId()));
+            // Make sure WindowManagerInter#getDisplayImePolicy is SHOW_IME_ON_DISPLAY is due to
+            // mForceDesktopModeOnExternalDisplays being SHOW_IME_ON_DISPLAY.
+            assertEquals(DISPLAY_IME_POLICY_FALLBACK_DISPLAY,
+                    mWm.mDisplayWindowSettings.getImePolicyLocked(dc));
+            assertEquals(DISPLAY_IME_POLICY_LOCAL, wmInternal.getDisplayImePolicy(dc.getDisplayId()));
         } finally {
             mWm.setForceDesktopModeOnExternalDisplays(false);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
index c3e1922..dfc2e35 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
@@ -31,7 +31,7 @@
 
 import com.android.internal.R;
 import com.android.internal.util.Preconditions;
-import com.android.server.wm.utils.FakeDeviceConfigInterface;
+import com.android.server.testutils.FakeDeviceConfigInterface;
 
 import org.junit.After;
 import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
index a9f6b50..f75c98f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
@@ -18,14 +18,28 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+import android.view.IWindowManager;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 
 import com.android.server.inputmethod.InputMethodManagerService;
 import com.android.server.inputmethod.InputMethodMenuController;
@@ -45,10 +59,34 @@
 public class InputMethodMenuControllerTest extends WindowTestsBase {
 
     private InputMethodMenuController mController;
+    private TestDisplayContent mSecondaryDisplay;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         mController = new InputMethodMenuController(mock(InputMethodManagerService.class));
+
+        // Mock addWindowTokenWithOptions to create a test window token.
+        IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
+        spyOn(wms);
+        doAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            final IBinder token = (IBinder) args[0];
+            final int windowType = (int) args[1];
+            new WindowToken(mWm, token, windowType, true /* persistOnEmpty */,
+                    mDefaultDisplay, true /* ownerCanManageAppTokens */, 1000 /* ownerUid */,
+                    false /* roundedCornerOverlay */, true /* fromClientToken */);
+            return WindowManagerGlobal.ADD_OKAY;
+        }).when(wms).addWindowTokenWithOptions(any(), anyInt(), anyInt(), any(), anyString());
+
+        mSecondaryDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1000).build();
+
+        // Mock DisplayManagerGlobal to return test display when obtaining Display instance.
+        final int displayId = mSecondaryDisplay.getDisplayId();
+        final Display display = mSecondaryDisplay.getDisplay();
+        DisplayManagerGlobal displayManagerGlobal = DisplayManagerGlobal.getInstance();
+        spyOn(displayManagerGlobal);
+        doReturn(display).when(displayManagerGlobal).getCompatibleDisplay(eq(displayId),
+                (Resources) any());
     }
 
     @Test
@@ -60,9 +98,9 @@
         // Obtain the context again and check they are the same instance and match the display
         // metrics of the secondary display.
         final Context contextOnSecondaryDisplay = mController.getSettingsContext(
-                mDisplayContent.getDisplayId());
+                mSecondaryDisplay.getDisplayId());
 
-        assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mDisplayContent);
+        assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay);
         assertThat(contextOnDefaultDisplay.getWindowContextToken())
                 .isEqualTo(contextOnSecondaryDisplay.getWindowContextToken());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index e514ac0..cd428e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -33,6 +33,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityStarter.Request;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
@@ -92,11 +93,12 @@
         final ActivityRecord source = new ActivityBuilder(mAtm).build();
         final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
         final ActivityOptions options = mock(ActivityOptions.class);
+        final Request request = new Request();
 
         mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS,
-                new LaunchParams());
+                new LaunchParams(), request);
         verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
-                eq(source), eq(options), anyInt(), any(), any());
+                eq(source), eq(options), anyInt(), any(), any(), eq(request));
     }
 
     /**
@@ -119,9 +121,9 @@
         mPersister.putLaunchParams(userId, name, expected);
 
         mController.calculate(activity.getTask(), null /*layout*/, activity, null /*source*/,
-                null /*options*/, PHASE_BOUNDS, new LaunchParams());
+                null /*options*/, PHASE_BOUNDS, new LaunchParams(), null /* request */);
         verify(positioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(),
-                eq(expected), any());
+                eq(expected), any(), any());
     }
 
     /**
@@ -132,16 +134,17 @@
         final LaunchParamsModifier
                 ignoredPositioner = mock(LaunchParamsModifier.class);
         final LaunchParamsModifier earlyExitPositioner =
-                (task, layout, activity, source, options, phase, currentParams, outParams)
+                (task, layout, activity, source, options, phase, currentParams, outParams, request)
                         -> RESULT_DONE;
 
         mController.registerModifier(ignoredPositioner);
         mController.registerModifier(earlyExitPositioner);
 
         mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams());
+                null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams(),
+                null /* request */);
         verify(ignoredPositioner, never()).onCalculate(any(), any(), any(), any(), any(), anyInt(),
-                any(), any());
+                any(), any(), any());
     }
 
     /**
@@ -157,20 +160,22 @@
         mController.registerModifier(firstPositioner);
 
         mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams());
+                null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams(),
+                null /* request */);
         verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(),
-                any(), any());
+                any(), any(), any());
 
         final LaunchParamsModifier secondPositioner = spy(earlyExitPositioner);
 
         mController.registerModifier(secondPositioner);
 
         mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
-                null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams());
+                null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams(),
+                null /* request */);
         verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(),
-                any(), any());
+                any(), any(), any());
         verify(secondPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(),
-                any(), any());
+                any(), any(), any());
     }
 
     /**
@@ -192,10 +197,10 @@
         mController.registerModifier(positioner2);
 
         mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
-                null /*options*/, PHASE_BOUNDS, new LaunchParams());
+                null /*options*/, PHASE_BOUNDS, new LaunchParams(), null /* request */);
 
         verify(positioner1, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(),
-                eq(positioner2.getLaunchParams()), any());
+                eq(positioner2.getLaunchParams()), any(), any());
     }
 
     /**
@@ -218,7 +223,7 @@
         final LaunchParams result = new LaunchParams();
 
         mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
-                null /*options*/, PHASE_BOUNDS, result);
+                null /*options*/, PHASE_BOUNDS, result, null /* request */);
 
         assertEquals(result, positioner2.getLaunchParams());
     }
@@ -237,17 +242,17 @@
 
         // VR activities should always land on default display.
         mController.calculate(null /*task*/, null /*layout*/, vrActivity /*activity*/,
-                null /*source*/, null /*options*/, PHASE_BOUNDS, result);
+                null /*source*/, null /*options*/, PHASE_BOUNDS, result, null /* request */);
         assertEquals(mRootWindowContainer.getDefaultTaskDisplayArea(),
                 result.mPreferredTaskDisplayArea);
 
         // Otherwise, always lands on VR 2D display.
         final ActivityRecord vr2dActivity = new ActivityBuilder(mAtm).build();
         mController.calculate(null /*task*/, null /*layout*/, vr2dActivity /*activity*/,
-                null /*source*/, null /*options*/, PHASE_BOUNDS, result);
+                null /*source*/, null /*options*/, PHASE_BOUNDS, result, null /* request */);
         assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea);
         mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
-                null /*options*/, PHASE_BOUNDS, result);
+                null /*options*/, PHASE_BOUNDS, result, null /* request */);
         assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea);
 
         mAtm.mVr2dDisplayId = INVALID_DISPLAY;
@@ -269,9 +274,9 @@
         final ActivityOptions options = mock(ActivityOptions.class);
 
         mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS,
-                new LaunchParams());
+                new LaunchParams(), null /* request */);
         verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
-                eq(source), eq(options), eq(PHASE_BOUNDS), any(), any());
+                eq(source), eq(options), eq(PHASE_BOUNDS), any(), any(), any());
     }
 
     /**
@@ -403,8 +408,9 @@
 
         @Override
         public int onCalculate(Task task, WindowLayout layout, ActivityRecord activity,
-                   ActivityRecord source, ActivityOptions options, int phase,
-                   LaunchParams currentParams, LaunchParams outParams) {
+                ActivityRecord source, ActivityOptions options, int phase,
+                LaunchParams currentParams, LaunchParams outParams,
+                Request request) {
             outParams.set(mParams);
             return mReturnVal;
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index d919d58..7812934 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -48,7 +47,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -58,12 +57,10 @@
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
-import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -100,14 +97,14 @@
     private static final int TEST_USER_0_ID = 0;
     private static final int TEST_USER_1_ID = 10;
     private static final int TEST_QUIET_USER_ID = 20;
-    private static final UserInfo DEFAULT_USER_INFO = new UserInfo();
+    private static final UserInfo DEFAULT_USER_INFO = new UserInfo(TEST_USER_0_ID,
+            "default", 0 /* flags */);
     private static final UserInfo QUIET_PROFILE_USER_INFO = new UserInfo(TEST_QUIET_USER_ID,
             "quiet_profile", null /* iconPath */, UserInfo.FLAG_QUIET_MODE,
             UserManager.USER_TYPE_PROFILE_MANAGED);
     private static final int INVALID_STACK_ID = 999;
 
     private TaskDisplayArea mTaskContainer;
-    private Task mStack;
     private TestTaskPersister mTaskPersister;
     private TestRecentTasks mRecentTasks;
     private TestRunningTasks mRunningTasks;
@@ -133,8 +130,6 @@
         mRunningTasks = new TestRunningTasks();
         mAtm.mTaskSupervisor.setRunningTasks(mRunningTasks);
 
-        mStack = mTaskContainer.createStack(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         mCallbacksRecorder = new CallbacksRecorder();
         mRecentTasks.registerCallback(mCallbacksRecorder);
 
@@ -214,9 +209,9 @@
 
         // Add N+1 tasks to ensure the previous task is trimmed
         mRecentTasks.add(mTasks.get(1));
+        triggerTrimAndAssertTrimmed(mTasks.get(0));
         verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
         verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean());
-        assertTrimmed(mTasks.get(0));
     }
 
     @Test
@@ -279,31 +274,6 @@
     }
 
     @Test
-    public void testAddTasksInVisibilityUpdate_expectNoTrim() {
-        mRecentTasks.setOnlyTestVisibleRange();
-        mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
-        mRecentTasks.add(mTasks.get(0));
-
-        doAnswer(invocation -> {
-            assertTrue(mSupervisor.inActivityVisibilityUpdate());
-            // Simulate an activity is resumed by EnsureActivitiesVisibleHelper. If its state is
-            // change to RESUMED, it will also be added to recents.
-            mRecentTasks.add(mTasks.get(1));
-            invocation.callRealMethod();
-            return null;
-        }).when(mSupervisor).endActivityVisibilityUpdate();
-
-        mTaskContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                false /* preserveWindows */, false /* notifyClients */, false /* userLeaving */);
-
-        assertFalse(mSupervisor.inActivityVisibilityUpdate());
-        assertThat(mCallbacksRecorder.mAdded).hasSize(2);
-        // Expect nothing is trimmed because we don't want the loop of ensure-visibility to be
-        // impacted by the arbitrary number of task removals.
-        assertNoTasksTrimmed();
-    }
-
-    @Test
     public void testAddTasksMultipleTasks_expectRemovedNoTrim() {
         // Add multiple same-affinity non-document tasks, ensure that it removes the other task,
         // but that it does not trim it
@@ -336,7 +306,7 @@
                 .setParentTask(mTaskContainer.getRootHomeTask()).build();
         Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
-                .setParentTask(mStack).build();
+                .build();
         mRecentTasks.add(task1);
         mRecentTasks.add(task2);
         assertThat(mCallbacksRecorder.mAdded).hasSize(2);
@@ -351,17 +321,15 @@
         // Test with undefined activity type since the type is not persisted by the task persister
         // and we want to ensure that a new task will match a restored task
         Task task1 = createTaskBuilder(".Task1")
+                .setActivityType(ACTIVITY_TYPE_UNDEFINED)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .build();
-        setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED);
         assertThat(task1.getActivityType()).isEqualTo(ACTIVITY_TYPE_UNDEFINED);
         mRecentTasks.add(task1);
         mCallbacksRecorder.clear();
 
         Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .build();
         assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType());
         mRecentTasks.add(task2);
@@ -375,18 +343,16 @@
     @Test
     public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() {
         Task task1 = createTaskBuilder(".Task1")
+                .setActivityType(ACTIVITY_TYPE_UNDEFINED)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .setUserId(TEST_USER_0_ID)
                 .build();
-        setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED);
         assertEquals(ACTIVITY_TYPE_UNDEFINED, task1.getActivityType());
         mRecentTasks.add(task1);
         mCallbacksRecorder.clear();
 
         Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .setUserId(TEST_USER_1_ID)
                 .build();
         assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType());
@@ -401,18 +367,15 @@
     public void testAddTaskCompatibleWindowingMode_expectRemove() {
         Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .build();
-        setTaskWindowingMode(task1, WINDOWING_MODE_UNDEFINED);
-        assertEquals(WINDOWING_MODE_UNDEFINED, task1.getWindowingMode());
+        doReturn(WINDOWING_MODE_UNDEFINED).when(task1).getWindowingMode();
         mRecentTasks.add(task1);
         mCallbacksRecorder.clear();
 
         Task task2 = createTaskBuilder(".Task1")
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .build();
-        setTaskWindowingMode(task2, WINDOWING_MODE_FULLSCREEN);
         assertEquals(WINDOWING_MODE_FULLSCREEN, task2.getWindowingMode());
         mRecentTasks.add(task2);
 
@@ -426,18 +389,16 @@
     @Test
     public void testAddTaskIncompatibleWindowingMode_expectNoRemove() {
         Task task1 = createTaskBuilder(".Task1")
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .build();
-        setTaskWindowingMode(task1, WINDOWING_MODE_FULLSCREEN);
         assertEquals(WINDOWING_MODE_FULLSCREEN, task1.getWindowingMode());
         mRecentTasks.add(task1);
 
         Task task2 = createTaskBuilder(".Task1")
+                .setWindowingMode(WINDOWING_MODE_PINNED)
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
-                .setParentTask(mStack)
                 .build();
-        setTaskWindowingMode(task2, WINDOWING_MODE_PINNED);
         assertEquals(WINDOWING_MODE_PINNED, task2.getWindowingMode());
         mRecentTasks.add(task2);
 
@@ -453,19 +414,19 @@
         // Add task to recents
         final String taskAffinity = "affinity";
         final int uid = 10123;
-        final Task task1 = createTaskBuilder(".Task1").setParentTask(mStack).build();
+        final Task task1 = createTaskBuilder(".Task1").build();
         task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
         mRecentTasks.add(task1);
 
         // Add another task to recents, and make sure the previous task was removed.
-        final Task task2 = createTaskBuilder(".Task2").setParentTask(mStack).build();
+        final Task task2 = createTaskBuilder(".Task2").build();
         task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
         mRecentTasks.add(task2);
         assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
                 true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
 
         // Add another single-instance task to recents, and make sure no task is removed.
-        final Task task3 = createTaskBuilder(".Task3").setParentTask(mStack).build();
+        final Task task3 = createTaskBuilder(".Task3").build();
         task3.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid,
                 LAUNCH_SINGLE_INSTANCE);
         mRecentTasks.add(task3);
@@ -521,6 +482,7 @@
         // Go home to trigger the removal of untracked tasks.
         mRecentTasks.add(createTaskBuilder(".Home").setParentTask(mTaskContainer.getRootHomeTask())
                 .build());
+        triggerIdleToTrim();
 
         // The task was added into recents again so it is not hidden and shouldn't be removed.
         assertNotNull(task1.getTopNonFinishingActivity());
@@ -615,7 +577,7 @@
         mRecentTasks.add(mTasks.get(2));
 
         // Ensure that the last task was trimmed as an inactive task
-        assertTrimmed(mTasks.get(0));
+        triggerTrimAndAssertTrimmed(mTasks.get(0));
     }
 
     @Test
@@ -630,7 +592,7 @@
         mRecentTasks.add(mTasks.get(1));
 
         // Ensure that the quiet user's tasks was trimmed once the new tasks were added
-        assertTrimmed(qt1, qt2);
+        triggerTrimAndAssertTrimmed(qt1, qt2);
     }
 
     @Test
@@ -645,12 +607,8 @@
         // Force a small sleep just beyond the session duration
         SystemClock.sleep(75);
 
-        Task t2 = createTaskBuilder(".Task2").build();
-        t2.touchActiveTime();
-        mRecentTasks.add(t2);
-
         // Assert that the old task has been removed due to being out of the active session
-        assertTrimmed(t1);
+        triggerTrimAndAssertTrimmed(t1);
     }
 
     @Test
@@ -672,15 +630,15 @@
         mRecentTasks.add(excludedTask2);
 
         // The last excluded task should be trimmed, while the first-most excluded task should not
-        assertTrimmed(excludedTask1);
+        triggerTrimAndAssertTrimmed(excludedTask1);
     }
 
     @Test
     public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
         // Create some set of tasks, some of which are visible and some are not
-        Task homeTask = setTaskActivityType(
-                createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
-                ACTIVITY_TYPE_HOME);
+        Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask")
+                .setParentTask(mTaskContainer.getRootHomeTask())
+                .build();
         homeTask.mUserSetupComplete = true;
         mRecentTasks.add(homeTask);
         Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
@@ -699,9 +657,9 @@
         Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
         t1.mUserSetupComplete = true;
         mRecentTasks.add(t1);
-        Task homeTask = setTaskActivityType(
-                createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
-                ACTIVITY_TYPE_HOME);
+        Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask")
+                .setParentTask(mTaskContainer.getRootHomeTask())
+                .build();
         homeTask.mUserSetupComplete = true;
         mRecentTasks.add(homeTask);
         Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
@@ -739,7 +697,7 @@
         mRecentTasks.add(mTasks.get(4));
 
         // Ensure that there are a minimum number of tasks regardless of session length
-        assertNoTasksTrimmed();
+        triggerTrimAndAssertNoTasksTrimmed();
     }
 
     @Test
@@ -754,7 +712,7 @@
         }
 
         // Ensure that only the last number of max tasks are kept
-        assertTrimmed(mTasks.get(0), mTasks.get(1));
+        triggerTrimAndAssertTrimmed(mTasks.get(0), mTasks.get(1));
     }
 
     /**
@@ -782,12 +740,12 @@
         mRecentTasks.add(mTasks.get(3));
 
         // excludedTask is not trimmed.
-        assertTrimmed(mTasks.get(0));
+        triggerTrimAndAssertTrimmed(mTasks.get(0));
 
         mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
 
         // Only visible tasks removed.
-        assertTrimmed(mTasks.get(0), mTasks.get(1), mTasks.get(2), mTasks.get(3));
+        triggerTrimAndAssertTrimmed(mTasks.get(0), mTasks.get(1), mTasks.get(2), mTasks.get(3));
     }
 
     @Test
@@ -910,7 +868,7 @@
         mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
         mRecentTasks.add(createTaskBuilder(".Task3").setParentTask(aboveHomeStack).build());
 
-        assertNoTasksTrimmed();
+        triggerTrimAndAssertNoTasksTrimmed();
     }
 
     @Test
@@ -932,7 +890,7 @@
         mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
         mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
 
-        assertTrimmed(behindHomeTask);
+        triggerTrimAndAssertTrimmed(behindHomeTask);
     }
 
     @Test
@@ -951,7 +909,7 @@
         mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayStack).build());
         mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeStack).build());
 
-        assertNoTasksTrimmed();
+        triggerTrimAndAssertNoTasksTrimmed();
     }
 
     @Test
@@ -978,14 +936,12 @@
         // Create some set of tasks, some of which are visible and some are not
         Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
         mRecentTasks.add(t1);
-        mRecentTasks.add(setTaskActivityType(
-                createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
-                ACTIVITY_TYPE_HOME));
+        mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".HomeTask")
+                .setParentTask(mTaskContainer.getRootHomeTask()).build());
         Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
         mRecentTasks.add(t2);
-        mRecentTasks.add(setTaskWindowingMode(
-                createTaskBuilder("com.android.pkg1", ".PipTask").build(),
-                WINDOWING_MODE_PINNED));
+        mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".PipTask")
+                .setWindowingMode(WINDOWING_MODE_PINNED).build());
         Task t3 = createTaskBuilder("com.android.pkg3", ".Task3").build();
         mRecentTasks.add(t3);
 
@@ -1005,7 +961,7 @@
 
         // Remove all the visible tasks and ensure that they are removed
         mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
-        assertTrimmed(t1, t2, t3, t4, t5, t6, t7);
+        triggerTrimAndAssertTrimmed(t1, t2, t3, t4, t5, t6, t7);
     }
 
     @Test
@@ -1030,7 +986,7 @@
 
         // Remove all the visible tasks and ensure that they are removed
         mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
-        assertTrimmed(t1, t2);
+        triggerTrimAndAssertTrimmed(t1, t2);
     }
 
     @Test
@@ -1040,7 +996,6 @@
         mRecentTasks.add(task);
         // Only keep the task in RecentTasks.
         task.removeIfPossible();
-        mStack.removeIfPossible();
 
         // The following APIs should not restore task from recents to the active list.
         assertNotRestoreTask(() -> mAtm.setFocusedTask(taskId));
@@ -1236,7 +1191,6 @@
     private TaskBuilder createTaskBuilder(String packageName, String className) {
         return new TaskBuilder(mAtm.mTaskSupervisor)
                 .setComponent(new ComponentName(packageName, className))
-                .setParentTask(mStack)
                 .setUserId(TEST_USER_0_ID);
     }
 
@@ -1253,27 +1207,19 @@
         return task;
     }
 
-    private Task setTaskActivityType(Task task,
-            @WindowConfiguration.ActivityType int activityType) {
-        Configuration config1 = new Configuration();
-        config1.windowConfiguration.setActivityType(activityType);
-        task.onConfigurationChanged(config1);
-        return task;
+    private void triggerIdleToTrim() {
+        doNothing().when(mAtm).scheduleAppGcsLocked();
+        final ActivityRecord r = mRootWindowContainer.topRunningActivity();
+        mSupervisor.activityIdleInternal(r != null ? r : mock(ActivityRecord.class),
+                false /* fromTimeout */, false /* processPausingActivities */, null /* config */);
     }
 
-    private Task setTaskWindowingMode(Task task,
-            @WindowConfiguration.WindowingMode int windowingMode) {
-        Configuration config1 = new Configuration();
-        config1.windowConfiguration.setWindowingMode(windowingMode);
-        task.onConfigurationChanged(config1);
-        return task;
+    private void triggerTrimAndAssertNoTasksTrimmed() {
+        triggerTrimAndAssertTrimmed();
     }
 
-    private void assertNoTasksTrimmed() {
-        assertTrimmed();
-    }
-
-    private void assertTrimmed(Task... tasks) {
+    private void triggerTrimAndAssertTrimmed(Task... tasks) {
+        triggerIdleToTrim();
         final ArrayList<Task> trimmed = mCallbacksRecorder.mTrimmed;
         final ArrayList<Task> removed = mCallbacksRecorder.mRemoved;
         assertWithMessage("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size())
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 40f73b1..5c39bd0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -322,7 +322,7 @@
         assertEquals(landActivity.findMainWindow(), win1);
 
         // Ensure that the display is in Landscape
-        landActivity.onDescendantOrientationChanged(landActivity.token, landActivity);
+        landActivity.onDescendantOrientationChanged(landActivity);
         assertEquals(Configuration.ORIENTATION_LANDSCAPE,
                 mDefaultDisplay.getConfiguration().orientation);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
deleted file mode 100644
index 25ba6db3..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.graphics.Color.RED;
-import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
-import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.LEFT;
-import static android.view.Gravity.RIGHT;
-import static android.view.Gravity.TOP;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
-import android.media.ImageReader;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
-import android.view.Display;
-import android.view.DisplayInfo;
-import android.view.View;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.widget.TextView;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.function.BooleanSupplier;
-
-/**
- * Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag.
- *
- * Build/Install/Run:
- *  atest WmTests:ScreenDecorWindowTests
- */
-// TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags.
-// TODO: Test non-Activity windows.
-@SmallTest
-@Presubmit
-public class ScreenDecorWindowTests {
-
-    private final Context mContext = getInstrumentation().getTargetContext();
-    private final Instrumentation mInstrumentation = getInstrumentation();
-
-    private WindowManager mWm;
-    private ArrayList<View> mWindows = new ArrayList<>();
-
-    private Activity mTestActivity;
-    private VirtualDisplay mDisplay;
-    private ImageReader mImageReader;
-
-    private int mDecorThickness;
-    private int mHalfDecorThickness;
-
-    @Before
-    public void setUp() {
-        final Pair<VirtualDisplay, ImageReader> result = createDisplay();
-        mDisplay = result.first;
-        mImageReader = result.second;
-        final Display display = mDisplay.getDisplay();
-        final Context dContext = mContext.createDisplayContext(display);
-        mWm = dContext.getSystemService(WindowManager.class);
-        mTestActivity = startActivityOnDisplay(TestActivity.class, display.getDisplayId());
-        final Point size = new Point();
-        mDisplay.getDisplay().getRealSize(size);
-        mDecorThickness = Math.min(size.x, size.y) / 3;
-        mHalfDecorThickness = mDecorThickness / 2;
-    }
-
-    @After
-    public void tearDown() {
-        while (!mWindows.isEmpty()) {
-            removeWindow(mWindows.get(0));
-        }
-        finishActivity(mTestActivity);
-        mDisplay.release();
-        mImageReader.close();
-    }
-
-    @Test
-    public void testScreenSides() {
-        // Decor on top
-        final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-
-        // Decor at the bottom
-        updateWindow(decorWindow, BOTTOM, MATCH_PARENT, mDecorThickness, 0, 0);
-        assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mDecorThickness);
-
-        // Decor to the left
-        updateWindow(decorWindow, LEFT, mDecorThickness, MATCH_PARENT, 0, 0);
-        assertInsetGreaterOrEqual(mTestActivity, LEFT, mDecorThickness);
-
-        // Decor to the right
-        updateWindow(decorWindow, RIGHT, mDecorThickness, MATCH_PARENT, 0, 0);
-        assertInsetGreaterOrEqual(mTestActivity, RIGHT, mDecorThickness);
-    }
-
-    // Decor windows (i.e windows using PRIVATE_FLAG_IS_SCREEN_DECOR) are no longer supported.
-    // PRIVATE_FLAG_IS_SCREEN_DECOR and related code will be deprecated/removed soon.
-    @Ignore
-    @Test
-    public void testMultipleDecors() {
-        // Test 2 decor windows on-top.
-        createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness);
-        assertInsetGreaterOrEqual(mTestActivity, TOP, mHalfDecorThickness);
-        createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-
-        // And one at the bottom.
-        createDecorWindow(BOTTOM, MATCH_PARENT, mHalfDecorThickness);
-        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-        assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mHalfDecorThickness);
-    }
-
-    @Test
-    public void testFlagChange() {
-        WindowInsets initialInsets = getInsets(mTestActivity);
-
-        final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        assertTopInsetEquals(mTestActivity, mDecorThickness);
-
-        updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
-                0, PRIVATE_FLAG_IS_SCREEN_DECOR);
-
-        // TODO: fix test and re-enable assertion.
-        // initialInsets was not actually immutable and just updated to the current insets,
-        // meaning this assertion never actually tested anything. Now that WindowInsets actually is
-        // immutable, it turns out the test was broken.
-        // assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
-
-        updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
-                PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
-        assertTopInsetEquals(mTestActivity, mDecorThickness);
-    }
-
-    @Test
-    public void testRemoval() {
-        WindowInsets initialInsets = getInsets(mTestActivity);
-
-        final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-
-        removeWindow(decorWindow);
-        assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
-    }
-
-    @Test
-    public void testProvidesInsetsTypes() {
-        int[] providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
-        final View win = createWindow("StatusBarSubPanel", TOP, MATCH_PARENT, mDecorThickness, RED,
-                FLAG_LAYOUT_IN_SCREEN, 0, providesInsetsTypes);
-
-        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-    }
-
-    private View createDecorWindow(int gravity, int width, int height) {
-        int[] providesInsetsTypes =
-                new int[]{gravity == TOP ? ITYPE_CLIMATE_BAR : ITYPE_EXTRA_NAVIGATION_BAR};
-        return createWindow("decorWindow", gravity, width, height, RED,
-                FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR, providesInsetsTypes);
-    }
-
-    private View createWindow(String name, int gravity, int width, int height, int color, int flags,
-            int privateFlags, int[] providesInsetsTypes) {
-
-        final View[] viewHolder = new View[1];
-        final int finalFlag = flags
-                | FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCHABLE;
-
-        // Needs to run on the UI thread.
-        Handler.getMain().runWithScissors(() -> {
-            final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                    width, height, TYPE_APPLICATION_OVERLAY, finalFlag, PixelFormat.OPAQUE);
-            lp.gravity = gravity;
-            lp.privateFlags |= privateFlags;
-            lp.providesInsetsTypes = providesInsetsTypes;
-
-            final TextView view = new TextView(mContext);
-            view.setText("ScreenDecorWindowTests - " + name);
-            view.setBackgroundColor(color);
-            mWm.addView(view, lp);
-            mWindows.add(view);
-            viewHolder[0] = view;
-        }, 0);
-
-        waitForIdle();
-        return viewHolder[0];
-    }
-
-    private void updateWindow(View v, int gravity, int width, int height,
-            int privateFlags, int privateFlagsMask) {
-        // Needs to run on the UI thread.
-        Handler.getMain().runWithScissors(() -> {
-            final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) v.getLayoutParams();
-            lp.gravity = gravity;
-            lp.width = width;
-            lp.height = height;
-            setPrivateFlags(lp, privateFlags, privateFlagsMask);
-
-            mWm.updateViewLayout(v, lp);
-        }, 0);
-
-        waitForIdle();
-    }
-
-    private void removeWindow(View v) {
-        Handler.getMain().runWithScissors(() -> mWm.removeView(v), 0);
-        mWindows.remove(v);
-        waitForIdle();
-    }
-
-    private WindowInsets getInsets(Activity a) {
-        return new WindowInsets(a.getWindow().getDecorView().getRootWindowInsets());
-    }
-
-    /**
-     * Set the flags of the window, as per the
-     * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
-     * flags.
-     *
-     * @param flags The new window flags (see WindowManager.LayoutParams).
-     * @param mask Which of the window flag bits to modify.
-     */
-    public void setPrivateFlags(WindowManager.LayoutParams lp, int flags, int mask) {
-        lp.flags = (lp.flags & ~mask) | (flags & mask);
-    }
-
-    /**
-     * Asserts the top inset of {@param activity} is equal to {@param expected} waiting as needed.
-     */
-    private void assertTopInsetEquals(Activity activity, int expected) {
-        waitForTopInsetEqual(activity, expected);
-        assertEquals(expected, getInsets(activity).getSystemWindowInsetTop());
-    }
-
-    private void waitForTopInsetEqual(Activity activity, int expected) {
-        waitFor(() -> getInsets(activity).getSystemWindowInsetTop() == expected);
-    }
-
-    /**
-     * Asserts the inset at {@param side} of {@param activity} is equal to {@param expected}
-     * waiting as needed.
-     */
-    private void assertInsetGreaterOrEqual(Activity activity, int side, int expected) {
-        waitForInsetGreaterOrEqual(activity, side, expected);
-
-        final WindowInsets insets = getInsets(activity);
-        switch (side) {
-            case TOP:
-                assertThat(insets.getSystemWindowInsetTop()).isAtLeast(expected);
-                break;
-            case BOTTOM:
-                assertThat(insets.getSystemWindowInsetBottom()).isAtLeast(expected);
-                break;
-            case LEFT:
-                assertThat(insets.getSystemWindowInsetLeft()).isAtLeast(expected);
-                break;
-            case RIGHT:
-                assertThat(insets.getSystemWindowInsetRight()).isAtLeast(expected);
-                break;
-        }
-    }
-
-    private void waitForInsetGreaterOrEqual(Activity activity, int side, int expected) {
-        waitFor(() -> {
-            final WindowInsets insets = getInsets(activity);
-            switch (side) {
-                case TOP: return insets.getSystemWindowInsetTop() >= expected;
-                case BOTTOM: return insets.getSystemWindowInsetBottom() >= expected;
-                case LEFT: return insets.getSystemWindowInsetLeft() >= expected;
-                case RIGHT: return insets.getSystemWindowInsetRight() >= expected;
-                default: return true;
-            }
-        });
-    }
-
-    private void waitFor(BooleanSupplier waitCondition) {
-        int retriesLeft = 5;
-        do {
-            if (waitCondition.getAsBoolean()) {
-                break;
-            }
-            SystemClock.sleep(500);
-        } while (retriesLeft-- > 0);
-    }
-
-    private void finishActivity(Activity a) {
-        if (a == null) {
-            return;
-        }
-        a.finish();
-        waitForIdle();
-    }
-
-    private void waitForIdle() {
-        mInstrumentation.waitForIdleSync();
-    }
-
-    private Activity startActivityOnDisplay(Class<?> cls, int displayId) {
-        final Intent intent = new Intent(mContext, cls);
-        intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchDisplayId(displayId);
-
-        final Activity activity = SystemUtil.runWithShellPermissionIdentity(
-                () -> mInstrumentation.startActivitySync(intent, options.toBundle()),
-                "android.permission.ACTIVITY_EMBEDDING");
-        waitForIdle();
-
-        assertEquals(displayId, activity.getDisplayId());
-        return activity;
-    }
-
-    private Pair<VirtualDisplay, ImageReader> createDisplay() {
-        final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
-        final DisplayInfo displayInfo = new DisplayInfo();
-        final Display defaultDisplay = dm.getDisplay(DEFAULT_DISPLAY);
-        defaultDisplay.getDisplayInfo(displayInfo);
-        final String name = "ScreenDecorWindowTests";
-        int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
-
-        final ImageReader imageReader = ImageReader.newInstance(
-                displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
-
-        final VirtualDisplay display = dm.createVirtualDisplay(name, displayInfo.logicalWidth,
-                displayInfo.logicalHeight, displayInfo.logicalDensityDpi, imageReader.getSurface(),
-                flags);
-
-        return Pair.create(display, imageReader);
-    }
-
-    public static class TestActivity extends Activity {
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index a4bf594..da00198 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -698,7 +698,7 @@
 
         // Update with new activity requested orientation and recompute bounds with no previous
         // size compat cache.
-        verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
+        verify(mTask).onDescendantOrientationChanged(same(newActivity));
         verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
 
         final Rect displayBounds = display.getBounds();
@@ -739,7 +739,7 @@
 
         // Update with new activity requested orientation and recompute bounds with no previous
         // size compat cache.
-        verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
+        verify(mTask).onDescendantOrientationChanged(same(newActivity));
         verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
 
         final Rect displayBounds = display.getBounds();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 98520bb..4f55322 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -35,6 +35,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.ActivityStarter.Request;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
 
@@ -42,6 +43,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.app.ActivityOptions;
 import android.content.pm.ActivityInfo;
@@ -265,6 +269,180 @@
                 mResult.mPreferredTaskDisplayArea);
     }
 
+    @Test
+    public void testUsesDisplayAreaFromTopMostActivityInApplicationIfAvailable() {
+        final String processName = "processName";
+        final int uid = 124214;
+        final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TaskDisplayArea expectedDisplayArea = secondScreen.getDefaultTaskDisplayArea();
+        final WindowProcessController controller = mock(WindowProcessController.class);
+
+        when(controller.getTopActivityDisplayArea()).thenReturn(expectedDisplayArea);
+
+        when(mActivity.getProcessName()).thenReturn(processName);
+        when(mActivity.getUid()).thenReturn(uid);
+        doReturn(controller)
+                .when(mSupervisor.mService)
+                .getProcessController(processName, uid);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(
+                null /* task */,
+                null /* layout */,
+                mActivity /* activity */,
+                null /* source */,
+                null /* options */,
+                -1 /* phase */,
+                mCurrent,
+                mResult,
+                null /* request */
+        ));
+
+        assertEquals(expectedDisplayArea, mResult.mPreferredTaskDisplayArea);
+    }
+
+    @Test
+    public void testUsesDisplayAreaFromLaunchingActivityIfApplicationLaunching() {
+        final String processName = "processName";
+        final int uid = 124214;
+        final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea();
+        final WindowProcessController controller = mock(WindowProcessController.class);
+
+        when(controller.getTopActivityDisplayArea()).thenReturn(expectedTaskDisplayArea);
+
+        when(mActivity.getProcessName()).thenReturn(processName);
+        when(mActivity.getUid()).thenReturn(uid);
+        doReturn(null)
+                .when(mSupervisor.mService)
+                .getProcessController(processName, uid);
+
+        doReturn(controller)
+                .when(mSupervisor.mService)
+                .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(
+                null /* task */,
+                null /* layout */,
+                mActivity /* activity */,
+                null /* source */,
+                null /* options */,
+                -1 /* phase */,
+                mCurrent,
+                mResult,
+                null /* request */
+        ));
+
+        assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea);
+    }
+
+    @Test
+    public void testDisplayAreaFromLaunchingActivityTakesPrecedence() {
+        final String processName = "processName";
+        final int uid = 124214;
+        final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TaskDisplayArea firstTaskDisplayArea = firstScreen.getDefaultTaskDisplayArea();
+        final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea();
+        final WindowProcessController controllerForLaunching = mock(WindowProcessController.class);
+        final WindowProcessController controllerForApplication =
+                mock(WindowProcessController.class);
+
+        when(mActivity.getProcessName()).thenReturn(processName);
+        when(mActivity.getUid()).thenReturn(uid);
+
+        when(controllerForApplication.getTopActivityDisplayArea()).thenReturn(firstTaskDisplayArea);
+        when(controllerForLaunching.getTopActivityDisplayArea())
+                .thenReturn(expectedTaskDisplayArea);
+
+        doReturn(controllerForApplication)
+                .when(mSupervisor.mService)
+                .getProcessController(processName, uid);
+        doReturn(controllerForLaunching)
+                .when(mSupervisor.mService)
+                .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(
+                null /* task */,
+                null /* layout */,
+                mActivity /* activity */,
+                null /* source */,
+                null /* options */,
+                -1 /* phase */,
+                mCurrent,
+                mResult,
+                null /* request */
+        ));
+
+        assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea);
+    }
+
+    @Test
+    public void testUsesDisplayAreaOriginalProcessAsLastResort() {
+        final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
+        final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea();
+        final Request request = new Request();
+        request.realCallingPid = 12412413;
+        request.realCallingUid = 235424;
+
+        final WindowProcessController controller = mock(WindowProcessController.class);
+
+        when(controller.getTopActivityDisplayArea()).thenReturn(expectedTaskDisplayArea);
+
+        doReturn(null)
+                .when(mSupervisor.mService)
+                .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid);
+
+        doReturn(null)
+                .when(mSupervisor.mService)
+                .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
+
+        doReturn(controller)
+                .when(mSupervisor.mService)
+                .getProcessController(request.realCallingPid, request.realCallingUid);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(
+                null /* task */,
+                null /* layout */,
+                mActivity /* activity */,
+                null /* source */,
+                null /* options */,
+                -1 /* phase */,
+                mCurrent,
+                mResult,
+                request
+        ));
+
+        assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea);
+    }
+
+    @Test
+    public void testUsesDefaultDisplayAreaIfWindowProcessControllerIsNotPresent() {
+        doReturn(null)
+                .when(mSupervisor.mService)
+                .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid);
+
+        doReturn(null)
+                .when(mSupervisor.mService)
+                .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(
+                null /* task */,
+                null /* layout */,
+                mActivity /* activity */,
+                null /* source */,
+                null /* options */,
+                -1 /* phase */,
+                mCurrent,
+                mResult,
+                null /* request */
+        ));
+
+        assertEquals(DEFAULT_DISPLAY, mResult.mPreferredTaskDisplayArea.getDisplayId());
+    }
+
     // =====================================
     // Launch Windowing Mode Related Tests
     // =====================================
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index d080fa0..61d4a47 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -70,6 +70,8 @@
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.view.DisplayInfo;
 
@@ -1064,12 +1066,12 @@
 
         activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
         assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
-        verify(display).onDescendantOrientationChanged(any(), same(task));
+        verify(display).onDescendantOrientationChanged(same(task));
         reset(display);
 
         display.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, task.getOrientation());
-        verify(display).onDescendantOrientationChanged(any(), same(task));
+        verify(display).onDescendantOrientationChanged(same(task));
     }
 
     private Task getTestTask() {
@@ -1097,7 +1099,7 @@
 
     private byte[] serializeToBytes(Task r) throws Exception {
         try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
-            final XmlSerializer serializer = Xml.newSerializer();
+            final TypedXmlSerializer serializer = Xml.newFastSerializer();
             serializer.setOutput(os, "UTF-8");
             serializer.startDocument(null, true);
             serializer.startTag(null, TASK_TAG);
@@ -1112,7 +1114,7 @@
 
     private Task restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
         try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
-            final XmlPullParser parser = Xml.newPullParser();
+            final TypedXmlPullParser parser = Xml.newFastPullParser();
             parser.setInput(reader);
             assertEquals(XmlPullParser.START_TAG, parser.next());
             assertEquals(TASK_TAG, parser.getName());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 165d468..4909b1d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 import static android.window.TransitionInfo.TRANSIT_HIDE;
@@ -46,16 +47,24 @@
 @RunWith(WindowTestRunner.class)
 public class TransitionTests extends WindowTestsBase {
 
+    private Transition createTestTransition(int transitType) {
+        TransitionController controller = mock(TransitionController.class);
+        BLASTSyncEngine sync = new BLASTSyncEngine(mWm);
+        return new Transition(transitType, 0 /* flags */, controller, sync);
+    }
+
     @Test
     public void testCreateInfo_NewTask() {
+        final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
         final Task newTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, mDisplayContent);
         final Task oldTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, mDisplayContent);
         final ActivityRecord closing = createActivityRecord(oldTask);
         final ActivityRecord opening = createActivityRecord(newTask);
-        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = new ArrayMap<>();
-        ArraySet<WindowContainer> participants = new ArraySet();
         // Start states.
         changes.put(newTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
         changes.put(oldTask, new Transition.ChangeInfo(true /* vis */, true /* exChg */));
@@ -70,29 +79,32 @@
         // Check basic both tasks participating
         participants.add(oldTask);
         participants.add(newTask);
-        TransitionInfo info =
-                Transition.calculateTransitionInfo(transitType, participants, changes);
+        ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertEquals(transitType, info.getType());
 
         // Check that children are pruned
         participants.add(opening);
         participants.add(closing);
-        info = Transition.calculateTransitionInfo(transitType, participants, changes);
+        targets = Transition.calculateTargets(participants, changes);
+        info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
 
         // Check combined prune and promote
         participants.remove(newTask);
-        info = Transition.calculateTransitionInfo(transitType, participants, changes);
+        targets = Transition.calculateTargets(participants, changes);
+        info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
 
         // Check multi promote
         participants.remove(oldTask);
-        info = Transition.calculateTransitionInfo(transitType, participants, changes);
+        targets = Transition.calculateTargets(participants, changes);
+        info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -100,6 +112,10 @@
 
     @Test
     public void testCreateInfo_NestedTasks() {
+        final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
         final Task newTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, mDisplayContent);
         final Task newNestedTask = createTaskInStack(newTask, 0);
@@ -109,8 +125,6 @@
         final ActivityRecord closing = createActivityRecord(oldTask);
         final ActivityRecord opening = createActivityRecord(newNestedTask);
         final ActivityRecord opening2 = createActivityRecord(newNestedTask2);
-        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = new ArrayMap<>();
-        ArraySet<WindowContainer> participants = new ArraySet();
         // Start states.
         changes.put(newTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
         changes.put(newNestedTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
@@ -130,8 +144,8 @@
         participants.add(oldTask);
         participants.add(opening);
         participants.add(opening2);
-        TransitionInfo info =
-                Transition.calculateTransitionInfo(transitType, participants, changes);
+        ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertEquals(transitType, info.getType());
         assertNotNull(info.getChange(newTask.mRemoteToken.toWindowContainerToken()));
@@ -139,7 +153,8 @@
 
         // Check that unchanging but visible descendant of sibling prevents promotion
         participants.remove(opening2);
-        info = Transition.calculateTransitionInfo(transitType, participants, changes);
+        targets = Transition.calculateTargets(participants, changes);
+        info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(newNestedTask.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(oldTask.mRemoteToken.toWindowContainerToken()));
@@ -147,6 +162,9 @@
 
     @Test
     public void testCreateInfo_DisplayArea() {
+        final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
         final Task showTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, mDisplayContent);
         final Task showNestedTask = createTaskInStack(showTask, 0);
@@ -155,8 +173,6 @@
         final DisplayArea tda = showTask.getDisplayArea();
         final ActivityRecord showing = createActivityRecord(showNestedTask);
         final ActivityRecord showing2 = createActivityRecord(showTask2);
-        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = new ArrayMap<>();
-        ArraySet<WindowContainer> participants = new ArraySet();
         // Start states.
         changes.put(showTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
         changes.put(showNestedTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
@@ -173,8 +189,8 @@
         // Check promotion to DisplayArea
         participants.add(showing);
         participants.add(showing2);
-        TransitionInfo info =
-                Transition.calculateTransitionInfo(transitType, participants, changes);
+        ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(1, info.getChanges().size());
         assertEquals(transitType, info.getType());
         assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
@@ -182,22 +198,21 @@
         ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
         // Check that organized tasks get reported even if not top
         showTask.mTaskOrganizer = mockOrg;
-        info = Transition.calculateTransitionInfo(transitType, participants, changes);
+        targets = Transition.calculateTargets(participants, changes);
+        info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
         assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));
         assertNotNull(info.getChange(showTask.mRemoteToken.toWindowContainerToken()));
         // Even if DisplayArea explicitly participating
         participants.add(tda);
-        info = Transition.calculateTransitionInfo(transitType, participants, changes);
+        targets = Transition.calculateTargets(participants, changes);
+        info = Transition.calculateTransitionInfo(transitType, targets, changes);
         assertEquals(2, info.getChanges().size());
     }
 
     @Test
     public void testCreateInfo_existenceChange() {
-        TransitionController controller = mock(TransitionController.class);
-        BLASTSyncEngine sync = new BLASTSyncEngine(mWm);
-        Transition transition = new Transition(
-                TRANSIT_OLD_TASK_OPEN, 0 /* flags */, controller, sync);
+        final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
 
         final Task openTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, mDisplayContent);
@@ -214,8 +229,9 @@
         opening.mVisibleRequested = true;
         closing.mVisibleRequested = false;
 
-        TransitionInfo info = Transition.calculateTransitionInfo(
-                0, transition.mParticipants, transition.mChanges);
+        ArraySet<WindowContainer> targets = Transition.calculateTargets(
+                transition.mParticipants, transition.mChanges);
+        TransitionInfo info = Transition.calculateTransitionInfo(0, targets, transition.mChanges);
         assertEquals(2, info.getChanges().size());
         // There was an existence change on open, so it should be OPEN rather than SHOW
         assertEquals(TRANSIT_OPEN,
@@ -224,4 +240,39 @@
         assertEquals(TRANSIT_HIDE,
                 info.getChange(closeTask.mRemoteToken.toWindowContainerToken()).getMode());
     }
+
+    @Test
+    public void testCreateInfo_ordering() {
+        final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
+        // pick some number with a high enough chance of being out-of-order when added to set.
+        final int taskCount = 6;
+
+        final Task[] tasks = new Task[taskCount];
+        for (int i = 0; i < taskCount; ++i) {
+            // Each add goes on top, so at the end of this, task[9] should be on top
+            tasks[i] = createTaskStackOnDisplay(WINDOWING_MODE_FREEFORM,
+                    ACTIVITY_TYPE_STANDARD, mDisplayContent);
+            final ActivityRecord act = createActivityRecord(tasks[i]);
+            // alternate so that the transition doesn't get promoted to the display area
+            act.mVisibleRequested = (i % 2) == 0; // starts invisible
+        }
+
+        // doesn't matter which order collected since participants is a set
+        for (int i = 0; i < taskCount; ++i) {
+            transition.collectExistenceChange(tasks[i]);
+            final ActivityRecord act = tasks[i].getTopMostActivity();
+            transition.collect(act);
+            tasks[i].getTopMostActivity().mVisibleRequested = (i % 2) != 0;
+        }
+
+        ArraySet<WindowContainer> targets = Transition.calculateTargets(
+                transition.mParticipants, transition.mChanges);
+        TransitionInfo info = Transition.calculateTransitionInfo(0, targets, transition.mChanges);
+        assertEquals(taskCount, info.getChanges().size());
+        // verify order is top-to-bottem
+        for (int i = 0; i < taskCount; ++i) {
+            assertEquals(tasks[taskCount - i - 1].mRemoteToken.toWindowContainerToken(),
+                    info.getChanges().get(i).getContainer());
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 3d8adbd..573da89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -56,7 +56,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.view.IRemoteAnimationFinishedCallback;
@@ -787,12 +786,11 @@
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = spy(builder.build());
 
-        final IBinder binder = mock(IBinder.class);
         final ActivityRecord activityRecord = mock(ActivityRecord.class);
         final TestWindowContainer child = root.addChildWindow();
 
-        child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, binder, activityRecord);
-        verify(root).onDescendantOrientationChanged(binder, activityRecord);
+        child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, activityRecord);
+        verify(root).onDescendantOrientationChanged(activityRecord);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
index 5210011..7a0ef0d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
@@ -32,7 +32,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.utils.FakeDeviceConfigInterface;
+import com.android.server.testutils.FakeDeviceConfigInterface;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 5afcedb..3057558 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -27,10 +27,13 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
 
 import android.Manifest;
 import android.app.IApplicationThread;
@@ -327,6 +330,45 @@
         return new ActivityBuilder(mAtm).setCreateTask(true).setUseProcess(wpc).build();
     }
 
+    @Test
+    public void testTopActivityDisplayAreaMatchesTopMostActivity_noActivities() {
+        assertNull(mWpc.getTopActivityDisplayArea());
+    }
+
+    @Test
+    public void testTopActivityDisplayAreaMatchesTopMostActivity_singleActivity() {
+        final ActivityRecord activityRecord = new ActivityBuilder(mSupervisor.mService).build();
+        final TaskDisplayArea expectedDisplayArea = mock(TaskDisplayArea.class);
+
+        when(activityRecord.getDisplayArea())
+                .thenReturn(expectedDisplayArea);
+
+        mWpc.addActivityIfNeeded(activityRecord);
+
+        assertEquals(expectedDisplayArea, mWpc.getTopActivityDisplayArea());
+    }
+
+    /**
+     * Test that top most activity respects z-order.
+     */
+    @Test
+    public void testTopActivityDisplayAreaMatchesTopMostActivity_multipleActivities() {
+        final ActivityRecord bottomRecord = new ActivityBuilder(mSupervisor.mService).build();
+        final TaskDisplayArea bottomDisplayArea = mock(TaskDisplayArea.class);
+        final ActivityRecord topRecord = new ActivityBuilder(mSupervisor.mService).build();
+        final TaskDisplayArea topDisplayArea = mock(TaskDisplayArea.class);
+
+        when(bottomRecord.getDisplayArea()).thenReturn(bottomDisplayArea);
+        when(topRecord.getDisplayArea()).thenReturn(topDisplayArea);
+        doReturn(-1).when(bottomRecord).compareTo(topRecord);
+        doReturn(1).when(topRecord).compareTo(bottomRecord);
+
+        mWpc.addActivityIfNeeded(topRecord);
+        mWpc.addActivityIfNeeded(bottomRecord);
+
+        assertEquals(topDisplayArea, mWpc.getTopActivityDisplayArea());
+    }
+
     private TestDisplayContent createTestDisplayContentInContainer() {
         return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 1d498bd..227eba2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -648,6 +648,8 @@
         win1.mSurfaceControl = mock(SurfaceControl.class);
         win1.mAttrs.surfaceInsets.set(1, 2, 3, 4);
         win1.getFrame().offsetTo(WINDOW_OFFSET, 0);
+        // Simulate layout
+        win1.mRelayoutCalled = true;
         win1.updateSurfacePosition(t);
         win1.getTransformationMatrix(values, matrix);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 8305381..6c046bd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -40,6 +40,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
@@ -80,6 +82,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManager.DisplayImePolicy;
 import android.window.ITaskOrganizer;
 
 import com.android.internal.util.ArrayUtils;
@@ -174,7 +177,7 @@
 
     private void createTestDisplay(UseTestDisplay annotation) {
         beforeCreateTestDisplay();
-        mDisplayContent = createNewDisplay(true /* supportIme */);
+        mDisplayContent = createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL);
 
         final boolean addAll = annotation.addAllCommonWindows();
         final @CommonTypes int[] requestedWindows = annotation.addWindows();
@@ -482,26 +485,26 @@
 
     /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
     DisplayContent createNewDisplay() {
-        return createNewDisplay(true /* supportIme */);
+        return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL);
     }
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
-    private DisplayContent createNewDisplay(boolean supportIme) {
-        return createNewDisplay(mDisplayInfo, supportIme);
+    private DisplayContent createNewDisplayWithImeSupport(@DisplayImePolicy int imePolicy) {
+        return createNewDisplay(mDisplayInfo, imePolicy);
     }
 
     /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
     DisplayContent createNewDisplay(DisplayInfo info) {
-        return createNewDisplay(info, true /* supportIme */);
+        return createNewDisplay(info, DISPLAY_IME_POLICY_LOCAL);
     }
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
-    private DisplayContent createNewDisplay(DisplayInfo info, boolean supportIme) {
+    private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy) {
         final DisplayContent display =
                 new TestDisplayContent.Builder(mAtm, info).build();
         final DisplayContent dc = display.mDisplayContent;
         // this display can show IME.
-        dc.mWmService.mDisplayWindowSettings.setShouldShowImeLocked(dc, supportIme);
+        dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy);
         return dc;
     }
 
@@ -516,7 +519,7 @@
         DisplayInfo displayInfo = new DisplayInfo();
         displayInfo.copyFrom(mDisplayInfo);
         displayInfo.state = displayState;
-        return createNewDisplay(displayInfo, true /* supportIme */);
+        return createNewDisplay(displayInfo, DISPLAY_IME_POLICY_LOCAL);
     }
 
     /** Creates a {@link TestWindowState} */
@@ -532,7 +535,7 @@
         displayInfo.copyFrom(mDisplayInfo);
         displayInfo.type = Display.TYPE_VIRTUAL;
         displayInfo.ownerUid = SYSTEM_UID;
-        return createNewDisplay(displayInfo, false /* supportIme */);
+        return createNewDisplay(displayInfo, DISPLAY_IME_POLICY_FALLBACK_DISPLAY);
     }
 
     IDisplayWindowInsetsController createDisplayWindowInsetsController() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 8e56e5b..aa36e47 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -82,6 +82,7 @@
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.CollectionUtils;
@@ -90,7 +91,6 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import java.io.BufferedReader;
@@ -178,6 +178,8 @@
     private final SparseArray<LinkedList<Event>> mReportedEvents = new SparseArray<>();
     final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
     final SparseArray<ActivityData> mVisibleActivities = new SparseArray();
+    private final ArraySet<UsageStatsManagerInternal.UsageEventListener> mUsageEventListeners =
+            new ArraySet<>();
 
     private static class ActivityData {
         private final String mTaskRootPackage;
@@ -202,8 +204,24 @@
                 }
             };
 
+    @VisibleForTesting
+    static class Injector {
+        AppStandbyInternal getAppStandbyController(Context context) {
+            return AppStandbyInternal.newAppStandbyController(
+                    UsageStatsService.class.getClassLoader(), context);
+        }
+    }
+
+    private final Injector mInjector;
+
     public UsageStatsService(Context context) {
+        this(context, new Injector());
+    }
+
+    @VisibleForTesting
+    UsageStatsService(Context context, Injector injector) {
         super(context);
+        mInjector = injector;
     }
 
     @Override
@@ -214,8 +232,7 @@
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mHandler = new H(BackgroundThread.get().getLooper());
 
-        mAppStandby = AppStandbyInternal.newAppStandbyController(
-                UsageStatsService.class.getClassLoader(), getContext());
+        mAppStandby = mInjector.getAppStandbyController(getContext());
 
         mAppTimeLimit = new AppTimeLimitController(
                 new AppTimeLimitController.TimeLimitCallbackListener() {
@@ -262,6 +279,11 @@
 
         publishLocalService(UsageStatsManagerInternal.class, new LocalService());
         publishLocalService(AppStandbyInternal.class, mAppStandby);
+        publishBinderServices();
+    }
+
+    @VisibleForTesting
+    void publishBinderServices() {
         publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
     }
 
@@ -928,7 +950,10 @@
             service.reportEvent(event);
         }
 
-        mAppStandby.reportEvent(event, userId);
+        final int size = mUsageEventListeners.size();
+        for (int i = 0; i < size; ++i) {
+            mUsageEventListeners.valueAt(i).onUsageEvent(userId, event);
+        }
     }
 
     /**
@@ -1151,6 +1176,25 @@
         }
     }
 
+    /**
+     * Called via the local interface.
+     */
+    private void registerListener(@NonNull UsageStatsManagerInternal.UsageEventListener listener) {
+        synchronized (mLock) {
+            mUsageEventListeners.add(listener);
+        }
+    }
+
+    /**
+     * Called via the local interface.
+     */
+    private void unregisterListener(
+            @NonNull UsageStatsManagerInternal.UsageEventListener listener) {
+        synchronized (mLock) {
+            mUsageEventListeners.remove(listener);
+        }
+    }
+
     private String buildFullToken(String packageName, String token) {
         final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1);
         sb.append(packageName);
@@ -2317,6 +2361,22 @@
         public boolean updatePackageMappingsData() {
             return UsageStatsService.this.updatePackageMappingsData();
         }
+
+        /**
+         * Register a listener that will be notified of every new usage event.
+         */
+        @Override
+        public void registerListener(@NonNull UsageEventListener listener) {
+            UsageStatsService.this.registerListener(listener);
+        }
+
+        /**
+         * Unregister a listener from being notified of every new usage event.
+         */
+        @Override
+        public void unregisterListener(@NonNull UsageEventListener listener) {
+            UsageStatsService.this.unregisterListener(listener);
+        }
     }
 
     private class MyPackageMonitor extends PackageMonitor {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 3af88e1..d585b23 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1213,9 +1213,11 @@
                     Slog.d(TAG, "Clear notification");
                     mUsbNotificationId = 0;
                 }
-                // Not relevant for automotive.
-                if (mContext.getPackageManager().hasSystemFeature(
+                // Not relevant for automotive and watch.
+                if ((mContext.getPackageManager().hasSystemFeature(
                         PackageManager.FEATURE_AUTOMOTIVE)
+                        || mContext.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_WATCH))
                         && id == SystemMessage.NOTE_USB_CHARGING) {
                     mUsbNotificationId = 0;
                     return;
diff --git a/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl b/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl
deleted file mode 100644
index 45e4c69..0000000
--- a/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-/** @hide */
-parcelable WifiApiServiceInfo {
-    String name;
-    IBinder binder;
-}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 5024ae2..835ecaa 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -361,7 +361,13 @@
      */
     public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 0x4000;
 
-    /* NEXT CAPABILITY: 0x8000 */
+    /**
+     * Flag indicating whether this {@link PhoneAccount} is capable of supporting the call composer
+     * functionality for enriched calls.
+     */
+    public static final int CAPABILITY_CALL_COMPOSER = 0x8000;
+
+    /* NEXT CAPABILITY: 0x10000 */
 
     /**
      * URI scheme for telephone number URIs.
@@ -1088,6 +1094,9 @@
         if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) {
             sb.append("AdhocConf");
         }
+        if (hasCapabilities(CAPABILITY_CALL_COMPOSER)) {
+            sb.append("CallComposer ");
+        }
         return sb.toString();
     }
 
diff --git a/telephony/java/android/telephony/CallForwardingInfo.java b/telephony/java/android/telephony/CallForwardingInfo.java
index 6ae6d00..aeac36e 100644
--- a/telephony/java/android/telephony/CallForwardingInfo.java
+++ b/telephony/java/android/telephony/CallForwardingInfo.java
@@ -86,7 +86,7 @@
      * Call forwarding reason types
      * @hide
      */
-    @IntDef(flag = true, prefix = { "REASON_" }, value = {
+    @IntDef(prefix = { "REASON_" }, value = {
         REASON_UNCONDITIONAL,
         REASON_BUSY,
         REASON_NO_REPLY,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 902dc06..baee473 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -53,9 +53,13 @@
     public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
 
     /**
-     * Extra included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate whether this is a
-     * rebroadcast on unlock. Defaults to {@code false} if not specified.
-     * @hide
+     * {@link #ACTION_CARRIER_CONFIG_CHANGED} is broadcast once on device bootup and then again when
+     * the device is unlocked. Direct-Boot-aware applications may use the first broadcast as an
+     * early signal that the carrier config has been loaded, but other applications will only
+     * receive the second broadcast, when the device is unlocked.
+     *
+     * This extra is included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate whether this is
+     * a rebroadcast on unlock.
      */
     public static final String EXTRA_REBROADCAST_ON_UNLOCK =
             "android.telephony.extra.REBROADCAST_ON_UNLOCK";
@@ -1881,9 +1885,8 @@
      *     "APN_1, ERROR_CODE_1 : CARRIER_ACTION_IDX_1, CARRIER_ACTION_IDX_2...",
      *     "APN_1, ERROR_CODE_2 : CARRIER_ACTION_IDX_1 "
      * }
-     * Where {@code APN_1} is a string defined in
-     * com.android.internal.telephony.PhoneConstants
-     * Example: "default"
+     * Where {@code APN_1} is an integer defined in {@link android.telephony.data.ApnSetting}
+     * (e.g. {@link android.telephony.data.ApnSetting#TYPE_DEFAULT}
      *
      * {@code ERROR_CODE_1} is an integer defined in android.telephony.DataFailCause
      * Example:
@@ -2030,8 +2033,16 @@
             "allow_hold_call_during_emergency_bool";
 
     /**
-     * Flag indicating whether the carrier supports RCS presence indication for
-     * User Capability Exchange (UCE).  When presence is supported, the device should use the
+     * Flag indicating whether or not the carrier supports the periodic exchange of phone numbers
+     * in the user's address book with the carrier's presence server in order to retrieve the RCS
+     * capabilities for each contact used in the RCS User Capability Exchange (UCE) procedure. See
+     * RCC.71, section 3 for more information.
+     * <p>
+     * The flag {@link Ims#KEY_ENABLE_PRESENCE_PUBLISH_BOOL} must also be enabled if this flag is
+     * enabled, as sending a periodic SIP PUBLISH with this device's RCS capabilities is a
+     * requirement for capability exchange to begin.
+     * <p>
+     * When presence is supported, the device should use the
      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the
      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate
      * whether each contact supports video calling.  The UI is made aware that presence is enabled
@@ -3847,12 +3858,27 @@
         public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL =
                 KEY_PREFIX + "ims_single_registration_required_bool";
 
+        /**
+         * A boolean flag specifying whether or not this carrier supports the device notifying the
+         * network of its RCS capabilities using the SIP PUBLISH procedure defined for User
+         * Capability Exchange (UCE). See RCC.71, section 3 for more information.
+         * <p>
+         * If this key's value is set to false, the procedure for RCS contact capability exchange
+         * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and
+         * {@link #KEY_USE_RCS_PRESENCE_BOOL} must also be set to false to ensure apps do not
+         * improperly think that capability exchange via SIP PUBLISH is enabled.
+         * <p> The default value for this key is {@code false}.
+         */
+        public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL =
+                KEY_PREFIX + "enable_presence_publish_bool";
+
         private Ims() {}
 
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000);
             defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
+            defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
             return defaults;
         }
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e341e0c..9288f79 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1575,177 +1575,157 @@
             "android.telephony.extra.PHONE_IN_ECM_STATE";
 
     /**
-     * <p>Broadcast Action: when data connections get redirected with validation failure.
-     * intended for sim/account status checks and only sent to the specified carrier app
-     * The intent will have the following extra values:</p>
+     * Broadcast action sent when a data connection is redirected with validation failure.
+     *
+     * This action is intended for sim/account status checks and only sent to the carrier apps
+     * specified in the carrier config for the subscription ID that's attached to this intent.
+     *
+     * The intent will have the following extra values:
      * <ul>
-     *   <li>{@link #EXTRA_APN_TYPE}</li><dd>A string with the apn type.</dd>
-     *   <li>{@link #EXTRA_APN_TYPE_INT}</li><dd>A integer with the apn type.</dd>
-     *   <li>{@link #EXTRA_REDIRECTION_URL}</li><dd>redirection url string</dd>
-     *   <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
+     *   <li>{@link #EXTRA_APN_TYPE}</li><dd>An integer indicating the apn type.</dd>
+     *   <li>{@link #EXTRA_REDIRECTION_URL}</li><dd>A string indicating the redirection url</dd>
+     *   <li>{@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX}</li>
+     *          <dd>The subscription ID on which the validation failure happened.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system.</p>
-     * @hide
      */
-    @SuppressLint("ActionValue")
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
-            "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED";
+            "android.telephony.action.CARRIER_SIGNAL_REDIRECTED";
 
     /**
-     * <p>Broadcast Action: when data connections setup fails.
-     * intended for sim/account status checks and only sent to the specified carrier app
-     * The intent will have the following extra values:</p>
+     * Broadcast action sent when a data connection setup fails.
+     *
+     * This action is intended for sim/account status checks and only sent to the carrier apps
+     * specified in the carrier config for the subscription ID that's attached to this intent.
+     *
+     * The intent will have the following extra values:
      * <ul>
-     *   <li>{@link #EXTRA_APN_TYPE}</li><dd>A string with the apn type.</dd>
-     *   <li>{@link #EXTRA_APN_TYPE_INT}</li><dd>A integer with the apn type.</dd>
-     *   <li>{@link #EXTRA_ERROR_CODE}</li><dd>A integer with dataFailCause.</dd>
-     *   <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
+     *   <li>{@link #EXTRA_APN_TYPE}</li><dd>An integer indicating the apn type.</dd>
+     *   <li>{@link #EXTRA_DATA_FAIL_CAUSE}</li><dd>A integer indicating the data fail cause.</dd>
+     *   <li>{@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX}</li>
+     *          <dd>The subscription ID on which the data setup failure happened.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
-     * @hide
      */
-    @SuppressLint("ActionValue")
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
-            "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
+            "android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
 
     /**
-     * <p>Broadcast Action: when pco value is available.
-     * intended for sim/account status checks and only sent to the specified carrier app
+     * Broadcast action sent when a PCO value becomes available from the modem.
+     *
+     * This action is intended for sim/account status checks and only sent to the carrier apps
+     * specified in the carrier config for the subscription ID that's attached to this intent.
+     *
      * The intent will have the following extra values:</p>
      * <ul>
-     *   <li>{@link #EXTRA_APN_TYPE}</li><dd>A string with the apn type.</dd>
-     *   <li>{@link #EXTRA_APN_TYPE_INT}</li><dd>A integer with the apn type.</dd>
-     *   <li>{@link #EXTRA_APN_PROTOCOL}</li><dd>A string with the protocol of the apn connection
-     *      (IP,IPV6, IPV4V6)</dd>
-     *   <li>{@link #EXTRA_APN_PROTOCOL_INT}</li><dd>A integer with the protocol of the apn
-     *      connection (IP,IPV6, IPV4V6)</dd>
-     *   <li>{@link #EXTRA_PCO_ID}</li><dd>An integer indicating the pco id for the data.</dd>
-     *   <li>{@link #EXTRA_PCO_VALUE}</li><dd>A byte array of pco data read from modem.</dd>
-     *   <li>subId</li><dd>Sub Id which associated the data connection.</dd>
+     *   <li>{@link #EXTRA_APN_TYPE}</li><dd>An integer indicating the apn type.</dd>
+     *   <li>{@link #EXTRA_APN_PROTOCOL}</li><dd>An integer indicating the protocol of the apn
+     *      connection</dd>
+     *   <li>{@link #EXTRA_PCO_ID}</li><dd>An integer indicating the PCO id for the data.</dd>
+     *   <li>{@link #EXTRA_PCO_VALUE}</li><dd>A byte array of PCO data read from modem.</dd>
+     *   <li>{@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX}</li>
+     *          <dd>The subscription ID for which the PCO info was received.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
-     * @hide
      */
-    @SuppressLint("ActionValue")
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
-            "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
+            "android.telephony.action.CARRIER_SIGNAL_PCO_VALUE";
 
     /**
-     * <p>Broadcast Action: when system default network available/unavailable with
-     * carrier-disabled mobile data. Intended for carrier apps to set/reset carrier actions when
-     * other network becomes system default network, Wi-Fi for example.
+     * Broadcast action sent when the availability of the system default network changes.
+     *
+     * @see ConnectivityManager#registerDefaultNetworkCallback(ConnectivityManager.NetworkCallback)
+     *
+     * This action is intended for carrier apps to set/reset carrier actions. It is only sent to the
+     * carrier apps specified in the carrier config for the subscription ID attached to this intent.
+     *
      * The intent will have the following extra values:</p>
      * <ul>
      *   <li>{@link #EXTRA_DEFAULT_NETWORK_AVAILABLE}</li>
-     *   <dd>A boolean indicates default network available.</dd>
-     *   <li>subId</li><dd>Sub Id which associated the default data.</dd>
+     *   <dd>{@code true} if the default network is now available, {@code false} otherwise.</dd>
+     *   <li>{@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX}</li>
+     *          <dd>The subscription ID on which the default network availability changed.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
-     * @hide
      */
-    @SuppressLint("ActionValue")
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE =
-            "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE";
+            "android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE";
 
     /**
-     * <p>Broadcast Action: when framework reset all carrier actions on sim load or absent.
-     * intended for carrier apps clean up (clear UI e.g.) and only sent to the specified carrier app
+     * Broadcast action sent when carrier apps should reset their internal state.
+     *
+     * Sent when certain events such as turning on/off mobile data, removing the SIM, etc. require
+     * carrier apps to reset their state.
+     *
+     * This action is intended to signal carrier apps to perform cleanup operations. It is only sent
+     * to the carrier apps specified in the carrier config for the subscription ID attached to
+     * this intent.
+     *
      * The intent will have the following extra values:</p>
      * <ul>
-     *   <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
+     *   <li>{@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX}</li>
+     *          <dd>The subscription ID for which state should be reset.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system.</p>
-     * @hide
      */
-    @SuppressLint("ActionValue")
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CARRIER_SIGNAL_RESET =
-            "com.android.internal.telephony.CARRIER_SIGNAL_RESET";
+            "android.telephony.action.CARRIER_SIGNAL_RESET";
 
-    // CARRIER_SIGNAL_ACTION extra keys
     /**
-     *  An string extra of redirected url upon {@link #ACTION_CARRIER_SIGNAL_REDIRECTED}.
-     *  @hide
+     * String extra containing the redirection URL sent with
+     * {@link #ACTION_CARRIER_SIGNAL_REDIRECTED}.
      */
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_REDIRECTION_URL = "redirectionUrl";
+    public static final String EXTRA_REDIRECTION_URL = "android.telephony.extra.REDIRECTION_URL";
 
     /**
-     *  An integer extra of error code upon {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED}.
-     *  Check {@link DataFailCause} for all possible values.
-     *  @hide
-     */
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_ERROR_CODE = "errorCode";
-
-    /**
-     *  An string extra of corresponding apn type upon
-     *  {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED},
-     *  {@link #ACTION_CARRIER_SIGNAL_REDIRECTED} and
-     *  {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts.
-     *  @deprecated This is kept for backward compatibility reason. Use {@link #EXTRA_APN_TYPE_INT}
-     *  instead.
+     * An integer extra containing the data fail cause.
      *
-     *  @hide
+     * Sent with {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED}. See {@link DataFailCause}
+     * for a list of possible values.
      */
-    @Deprecated
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_APN_TYPE = "apnType";
+    public static final String EXTRA_DATA_FAIL_CAUSE = "android.telephony.extra.DATA_FAIL_CAUSE";
 
     /**
-     *  An string integer of corresponding apn type upon
-     *  {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED},
-     *  {@link #ACTION_CARRIER_SIGNAL_REDIRECTED} and
-     *  {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts.
-     *  Check {@link ApnSetting} TYPE_* for its values.
-     *  @hide
-     */
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_APN_TYPE_INT = "apnTypeInt";
-
-    /**
-     *  An string extra with the protocol of the apn connection (IP,IPV6, IPV4V6) upon
-     *  {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts.
-     *  @deprecated This is kept for backward compatibility reason.
-     *  Use {@link #EXTRA_APN_PROTOCOL_INT} instead.
+     * An integer extra containing the APN type.
      *
-     *  @hide
+     * Sent with the  {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED},
+     * {@link #ACTION_CARRIER_SIGNAL_REDIRECTED}, and {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE}
+     * broadcasts.
+     * See the {@code TYPE_} constants in {@link ApnSetting} for a list of possible values.
      */
-    @Deprecated
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_APN_PROTOCOL = "apnProto";
+    public static final String EXTRA_APN_TYPE = "android.telephony.extra.APN_TYPE";
 
     /**
-     *  An integer extra with the protocol of the apn connection (IP,IPV6, IPV4V6) upon
-     *  {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts.
-     *  Check {@link ApnSetting} PROTOCOL_* for its values.
-     *  @hide
+     * An integer extra containing the protocol of the apn connection.
+     *
+     * Sent with the {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcast.
+     * See the {@code PROTOCOL_*} constants in {@link ApnSetting} for a list of possible values.
      */
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_APN_PROTOCOL_INT = "apnProtoInt";
+    public static final String EXTRA_APN_PROTOCOL = "android.telephony.extra.APN_PROTOCOL";
 
     /**
-     *  An integer extra indicating the pco id for the data upon
-     *  {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts.
-     *  @hide
+     * An integer extra indicating the ID for the PCO data.
+     * Sent with the {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcast.
      */
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_PCO_ID = "pcoId";
+    public static final String EXTRA_PCO_ID = "android.telephony.extra.PCO_ID";
 
     /**
-     *  An extra of byte array of pco data read from modem upon
-     *  {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts.
-     *  @hide
+     * A byte array extra containing PCO data read from the modem.
+     * Sent with the {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcast.
      */
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_PCO_VALUE = "pcoValue";
+    public static final String EXTRA_PCO_VALUE = "android.telephony.extra.PCO_VALUE";
 
     /**
-     *  An boolean extra indicating default network available upon
-     *  {@link #ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE} broadcasts.
-     *  @hide
+     * A boolean extra indicating the availability of the default network.
+     * Sent with the {@link #ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE} broadcast.
      */
-    @SuppressLint("ActionValue")
-    public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable";
+    public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE =
+            "android.telephony.extra.DEFAULT_NETWORK_AVAILABLE";
 
     /**
      * <p>Broadcast Action: The emergency call state is changed.
@@ -9483,7 +9463,7 @@
     }
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "CDMA_SUBSCRIPTION_" }, value = {
+    @IntDef(prefix = { "CDMA_SUBSCRIPTION_" }, value = {
             CDMA_SUBSCRIPTION_UNKNOWN,
             CDMA_SUBSCRIPTION_RUIM_SIM,
             CDMA_SUBSCRIPTION_NV
diff --git a/telephony/java/android/telephony/ims/DelegateMessageCallback.java b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
index beec4a6..0d82a54 100644
--- a/telephony/java/android/telephony/ims/DelegateMessageCallback.java
+++ b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.telephony.ims.stub.SipDelegate;
 
 /**
@@ -30,6 +31,7 @@
  * </ul>
  * @hide
  */
+@SystemApi
 public interface DelegateMessageCallback {
 
     /**
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
index 4facfa7..3558a9b 100644
--- a/telephony/java/android/telephony/ims/DelegateRegistrationState.java
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -18,14 +18,14 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -34,6 +34,7 @@
  * ImsService.
  * @hide
  */
+@SystemApi
 public final class DelegateRegistrationState implements Parcelable {
 
     /**
@@ -114,14 +115,14 @@
     })
     public @interface DeregisteringReason {}
 
-    private final ArrayList<String> mRegisteredTags = new ArrayList<>();
-    private final ArrayList<FeatureTagState> mDeregisteringTags = new ArrayList<>();
-    private final ArrayList<FeatureTagState> mDeregisteredTags = new ArrayList<>();
+    private ArraySet<String> mRegisteredTags = new ArraySet<>();
+    private final ArraySet<FeatureTagState> mDeregisteringTags = new ArraySet<>();
+    private final ArraySet<FeatureTagState> mDeregisteredTags = new ArraySet<>();
 
     /**
      * Builder used to create new instances of {@link DelegateRegistrationState}.
      */
-    public static class Builder {
+    public static final class Builder {
 
         private final DelegateRegistrationState mState;
 
@@ -135,10 +136,8 @@
          * @param featureTag The IMS media feature tag included in the current IMS registration.
          * @return The in-progress Builder instance for RegistrationState.
          */
-        public Builder addRegisteredFeatureTag(@NonNull String featureTag) {
-            if (!mState.mRegisteredTags.contains(featureTag)) {
-                mState.mRegisteredTags.add(featureTag);
-            }
+        public @NonNull Builder addRegisteredFeatureTag(@NonNull String featureTag) {
+            mState.mRegisteredTags.add(featureTag);
             return this;
         }
 
@@ -148,7 +147,8 @@
          * @param featureTags The IMS media feature tags included in the current IMS registration.
          * @return The in-progress Builder instance for RegistrationState.
          */
-        public Builder addRegisteredFeatureTags(@NonNull Set<String> featureTags) {
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public @NonNull Builder addRegisteredFeatureTags(@NonNull Set<String> featureTags) {
             mState.mRegisteredTags.addAll(featureTags);
             return this;
         }
@@ -167,13 +167,9 @@
          *         The availability of the feature tag depends on the {@link DeregisteringReason}.
          * @return The in-progress Builder instance for RegistrationState.
          */
-        public Builder addDeregisteringFeatureTag(@NonNull String featureTag,
+        public @NonNull Builder addDeregisteringFeatureTag(@NonNull String featureTag,
                 @DeregisteringReason int reason) {
-            boolean ftExists = mState.mDeregisteringTags.stream().anyMatch(
-                    f -> f.getFeatureTag().equals(featureTag));
-            if (!ftExists) {
-                mState.mDeregisteringTags.add(new FeatureTagState(featureTag, reason));
-            }
+            mState.mDeregisteringTags.add(new FeatureTagState(featureTag, reason));
             return this;
         }
 
@@ -185,20 +181,16 @@
          * @param reason The reason why the media feature tag has been deregistered.
          * @return The in-progress Builder instance for RegistrationState.
          */
-        public Builder addDeregisteredFeatureTag(@NonNull String featureTag,
+        public @NonNull Builder addDeregisteredFeatureTag(@NonNull String featureTag,
                 @DeregisteredReason int reason) {
-            boolean ftExists = mState.mDeregisteredTags.stream().anyMatch(
-                    f -> f.getFeatureTag().equals(featureTag));
-            if (!ftExists) {
-                mState.mDeregisteredTags.add(new FeatureTagState(featureTag, reason));
-            }
+            mState.mDeregisteredTags.add(new FeatureTagState(featureTag, reason));
             return this;
         }
 
         /**
          * @return the finalized instance.
          */
-        public DelegateRegistrationState build() {
+        public @NonNull DelegateRegistrationState build() {
             return mState;
         }
     }
@@ -212,7 +204,7 @@
      * Used for unparcelling only.
      */
     private DelegateRegistrationState(Parcel source) {
-        source.readList(mRegisteredTags, null /*classloader*/);
+        mRegisteredTags = (ArraySet<String>) source.readArraySet(null);
         readStateFromParcel(source, mDeregisteringTags);
         readStateFromParcel(source, mDeregisteredTags);
     }
@@ -268,7 +260,8 @@
         return new ArraySet<>(mDeregisteredTags);
     }
 
-    public static final Creator<DelegateRegistrationState> CREATOR =
+
+    public static final @NonNull Creator<DelegateRegistrationState> CREATOR =
             new Creator<DelegateRegistrationState>() {
         @Override
         public DelegateRegistrationState createFromParcel(Parcel source) {
@@ -287,13 +280,13 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeList(mRegisteredTags);
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeArraySet(mRegisteredTags);
         writeStateToParcel(dest, mDeregisteringTags);
         writeStateToParcel(dest, mDeregisteredTags);
     }
 
-    private void writeStateToParcel(Parcel dest, List<FeatureTagState> state) {
+    private void writeStateToParcel(Parcel dest, Set<FeatureTagState> state) {
         dest.writeInt(state.size());
         for (FeatureTagState s : state) {
             dest.writeString(s.getFeatureTag());
@@ -301,11 +294,12 @@
         }
     }
 
-    private void readStateFromParcel(Parcel source, List<FeatureTagState> emptyState) {
+    private void readStateFromParcel(Parcel source, Set<FeatureTagState> emptyState) {
         int len = source.readInt();
         for (int i = 0; i < len; i++) {
             String ft = source.readString();
             int reason = source.readInt();
+
             emptyState.add(new FeatureTagState(ft, reason));
         }
     }
diff --git a/telephony/java/android/telephony/ims/DelegateRequest.java b/telephony/java/android/telephony/ims/DelegateRequest.java
index 73d0840..c322d92 100644
--- a/telephony/java/android/telephony/ims/DelegateRequest.java
+++ b/telephony/java/android/telephony/ims/DelegateRequest.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.ims.stub.SipDelegate;
@@ -31,6 +32,7 @@
  * SipDelegateConnection given back to the requesting application.
  * @hide
  */
+@SystemApi
 public final class DelegateRequest implements Parcelable {
 
     private final ArrayList<String> mFeatureTags;
@@ -52,7 +54,7 @@
      * @return the list of IMS feature tag associated with this DelegateRequest in the format
      * defined in RCC.07 section 2.6.1.3.
      */
-    public Set<String> getFeatureTags() {
+    public @NonNull Set<String> getFeatureTags() {
         return new ArraySet<>(mFeatureTags);
     }
 
@@ -70,7 +72,7 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeList(mFeatureTags);
     }
 
diff --git a/telephony/java/android/telephony/ims/DelegateStateCallback.java b/telephony/java/android/telephony/ims/DelegateStateCallback.java
index 0f1afc4..fb65949 100644
--- a/telephony/java/android/telephony/ims/DelegateStateCallback.java
+++ b/telephony/java/android/telephony/ims/DelegateStateCallback.java
@@ -18,10 +18,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.telephony.ims.stub.SipDelegate;
 import android.telephony.ims.stub.SipTransportImplBase;
 
-import java.util.List;
+import java.util.Set;
 
 /**
  * Callback interface to notify a remote application of the following:
@@ -34,26 +35,24 @@
  * </ul>
  * @hide
  */
+@SystemApi
 public interface DelegateStateCallback {
 
     /**
      * This must be called by the ImsService after {@link SipTransportImplBase#createSipDelegate} is
      * called by the framework to notify the framework and remote application that the
      * {@link SipDelegate} has been successfully created.
-     *
-     * @param delegate The SipDelegate created to service the DelegateRequest.
-     * @param deniedTags A List of {@link FeatureTagState}, which contains the feature tags
+     *  @param delegate The SipDelegate created to service the DelegateRequest.
+     * @param deniedTags A Set of {@link FeatureTagState}s, which contain the feature tags
      *    associated with this {@link SipDelegate} that have no access to send/receive SIP messages
      *    as well as a reason for why the feature tag is denied. For more information on the reason
      *    why the feature tag was denied access, see the
      *    {@link SipDelegateManager.DeniedReason} reasons. This is considered a permanent denial due
      *    to this {@link SipDelegate} not supporting a feature or this ImsService already
      *    implementing this feature elsewhere. If all features of this {@link SipDelegate} are
-     *    denied, {@link #onCreated(SipDelegate, List)} should still be called as the framework will
-     *    later call {@link SipTransportImplBase#destroySipDelegate(SipDelegate, int)} to clean the
-     *    delegate up.
+     *    denied, this method should still be called.
      */
-    void onCreated(@NonNull SipDelegate delegate, @Nullable List<FeatureTagState> deniedTags);
+    void onCreated(@NonNull SipDelegate delegate, @Nullable Set<FeatureTagState> deniedTags);
 
     /**
      * This must be called by the ImsService after the framework calls
diff --git a/telephony/java/android/telephony/ims/FeatureTagState.java b/telephony/java/android/telephony/ims/FeatureTagState.java
index 060be6f..3622065 100644
--- a/telephony/java/android/telephony/ims/FeatureTagState.java
+++ b/telephony/java/android/telephony/ims/FeatureTagState.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.ims.stub.DelegateConnectionStateCallback;
@@ -39,6 +40,7 @@
  * currently available.
  * @hide
  */
+@SystemApi
 public final class FeatureTagState implements Parcelable {
 
     private final String mFeatureTag;
@@ -48,8 +50,8 @@
      * Associate an IMS feature tag with its current state. See {@link DelegateRegistrationState}
      * and {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged(
      * DelegateRegistrationState, List)} and
-     * {@link DelegateStateCallback#onCreated(SipDelegate, List)} for examples on how and when this
-     * is used.
+     * {@link DelegateStateCallback#onCreated(SipDelegate, java.util.Set)} for examples on how and
+     * when this is used.
      *
      * @param featureTag The IMS feature tag that is deregistered, in the process of
      *                   deregistering, or denied.
@@ -93,12 +95,12 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mFeatureTag);
         dest.writeInt(mState);
     }
 
-    public static final Creator<FeatureTagState> CREATOR = new Creator<FeatureTagState>() {
+    public static final @NonNull Creator<FeatureTagState> CREATOR = new Creator<FeatureTagState>() {
         @Override
         public FeatureTagState createFromParcel(Parcel source) {
             return new FeatureTagState(source);
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 1b51936..aaa68d6 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -207,6 +208,42 @@
             "android.telephony.ims.extra.RETRY_CALL_FAIL_NETWORKTYPE";
 
     /**
+     * Extra for the call composer call priority, either {@link ImsCallProfile#PRIORITY_NORMAL} or
+     * {@link ImsCallProfile#PRIORITY_URGENT}. It can be set via
+     * {@link #setCallExtraInt(String, int)}.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY";
+
+    // TODO(hallliu) remove the reference to the maximum length and update it later.
+    /**
+     * Extra for the call composer call subject, a string of maximum length 60 characters.
+     * It can be set via {@link #setCallExtra(String, String)}.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT";
+
+    /**
+     * Extra for the call composer call location, an {@Link android.location.Location} parcelable
+     * class to represent the geolocation as a latitude and longitude pair. It can be set via
+     * {@link #setCallExtraParcelable(String, Parcelable)}.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION";
+
+    /**
+     * Extra for the call composer picture URL, a String that indicates the URL on the carrier’s
+     * server infrastructure to get the picture. It can be set via
+     * {@link #setCallExtra(String, String)}.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
+
+    /**
      * Values for EXTRA_OIR / EXTRA_CNAP
      */
     /**
@@ -244,6 +281,21 @@
      */
     public static final int DIALSTRING_USSD = 2;
 
+    // Values for EXTRA_PRIORITY
+    /**
+     * Indicates the call composer call priority is normal.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_NORMAL = 0;
+
+    /**
+     * Indicates the call composer call priority is urgent.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_URGENT = 1;
+
     /**
      * Call is not restricted on peer side and High Definition media is supported
      */
@@ -588,6 +640,19 @@
         return mCallExtras.getInt(name, defaultValue);
     }
 
+    /**
+     * Get the call extras (Parcelable), given the extra name.
+     * @param name call extra name
+     * @return the corresponding call extra Parcelable or null if not applicable
+     */
+    @Nullable
+    public <T extends Parcelable> T getCallExtraParcelable(@Nullable String name) {
+        if (mCallExtras != null) {
+            return mCallExtras.getParcelable(name);
+        }
+        return null;
+    }
+
     public void setCallExtra(String name, String value) {
         if (mCallExtras != null) {
             mCallExtras.putString(name, value);
@@ -607,6 +672,17 @@
     }
 
     /**
+     * Set the call extra value (Parcelable), given the call extra name.
+     * @param name call extra name
+     * @param parcelable call extra value
+     */
+    public void setCallExtraParcelable(@NonNull String name, @NonNull Parcelable parcelable) {
+        if (mCallExtras != null) {
+            mCallExtras.putParcelable(name, parcelable);
+        }
+    }
+
+    /**
      * Set the call restrict cause, which provides the reason why a call has been restricted from
      * using High Definition media.
      */
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index fdf636c..c663e39 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -49,8 +49,7 @@
     public static final int CALL_STATE_TERMINATED = 2;
 
     /**@hide*/
-    @IntDef(flag = true,
-            value = {
+    @IntDef(value = {
                     CALL_STATE_CONFIRMED,
                     CALL_STATE_TERMINATED
             },
@@ -59,8 +58,7 @@
     public @interface ExternalCallState {}
 
     /**@hide*/
-    @IntDef(flag = true,
-            value = {
+    @IntDef(value = {
                     ImsCallProfile.CALL_TYPE_VOICE,
                     ImsCallProfile.CALL_TYPE_VT_TX,
                     ImsCallProfile.CALL_TYPE_VT_RX,
diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java
index fb8e5d3..868dea6a 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -72,7 +72,7 @@
 
 
     /**@hide*/
-    @IntDef(flag = true, prefix = {"SS_"}, value = {
+    @IntDef(prefix = {"SS_"}, value = {
             SS_ACTIVATION,
             SS_DEACTIVATION,
             SS_INTERROGATION,
@@ -89,7 +89,7 @@
     public static final int SS_ERASURE = 4;
 
     /**@hide*/
-    @IntDef(flag = true, prefix = {"SS_"}, value = {
+    @IntDef(prefix = {"SS_"}, value = {
             SS_ALL_TELE_AND_BEARER_SERVICES,
             SS_ALL_TELESEVICES,
             SS_TELEPHONY,
@@ -190,7 +190,7 @@
     public static final int RESULT_SUCCESS = 0;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "SS_" }, value = {
+    @IntDef(prefix = { "SS_" }, value = {
             SS_CFU,
             SS_CF_BUSY,
             SS_CF_NO_REPLY,
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index d12a6ae..5848be8 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -105,10 +105,17 @@
     public @interface RequestResult {}
 
     /**
+     * The base class of {@link OptionsBuilder} and {@link PresenceBuilder}
+     */
+    public static abstract class RcsUcsCapabilityBuilder {
+        public abstract @NonNull RcsContactUceCapability build();
+    }
+
+    /**
      * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
      * queried through SIP OPTIONS.
      */
-    public static class OptionsBuilder {
+    public static class OptionsBuilder extends RcsUcsCapabilityBuilder {
 
         private final RcsContactUceCapability mCapabilities;
 
@@ -155,6 +162,7 @@
         /**
          * @return the constructed instance.
          */
+        @Override
         public @NonNull RcsContactUceCapability build() {
             return mCapabilities;
         }
@@ -164,7 +172,7 @@
      * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
      * queried through a presence server.
      */
-    public static class PresenceBuilder {
+    public static class PresenceBuilder extends RcsUcsCapabilityBuilder {
 
         private final RcsContactUceCapability mCapabilities;
 
@@ -205,6 +213,7 @@
         /**
          * @return the RcsContactUceCapability instance.
          */
+        @Override
         public @NonNull RcsContactUceCapability build() {
             return mCapabilities;
         }
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index ada0696..8d7742b 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -76,39 +76,46 @@
      * @hide
      */
     public static final int ERROR_GENERIC_FAILURE = 1;
+
     /**
      * The carrier network does not have UCE support enabled for this subscriber.
      * @hide
      */
     public static final int ERROR_NOT_ENABLED = 2;
+
     /**
      * The data network that the device is connected to does not support UCE currently (e.g. it is
      * 1x only currently).
      * @hide
      */
     public static final int ERROR_NOT_AVAILABLE = 3;
+
     /**
      * The network has responded with SIP 403 error and a reason "User not registered."
      * @hide
      */
     public static final int ERROR_NOT_REGISTERED = 4;
+
     /**
      * The network has responded to this request with a SIP 403 error and reason "not authorized for
      * presence" for this subscriber.
      * @hide
      */
     public static final int ERROR_NOT_AUTHORIZED = 5;
+
     /**
      * The network has responded to this request with a SIP 403 error and no reason.
      * @hide
      */
     public static final int ERROR_FORBIDDEN = 6;
+
     /**
      * The contact URI requested is not provisioned for VoLTE or it is not known as an IMS
      * subscriber to the carrier network.
      * @hide
      */
     public static final int ERROR_NOT_FOUND = 7;
+
     /**
      * The capabilities request contained too many URIs for the carrier network to handle. Retry
      * with a lower number of contact numbers. The number varies per carrier.
@@ -116,22 +123,32 @@
      */
     // TODO: Try to integrate this into the API so that the service will split based on carrier.
     public static final int ERROR_REQUEST_TOO_LARGE = 8;
+
     /**
      * The network did not respond to the capabilities request before the request timed out.
      * @hide
      */
     public static final int ERROR_REQUEST_TIMEOUT = 10;
+
     /**
      * The request failed due to the service having insufficient memory.
      * @hide
      */
     public static final int ERROR_INSUFFICIENT_MEMORY = 11;
+
     /**
      * The network was lost while trying to complete the request.
      * @hide
      */
     public static final int ERROR_LOST_NETWORK = 12;
 
+    /**
+     * The network is temporarily unavailable or busy. Retries should only be done after the retry
+     * time returned in {@link CapabilitiesCallback#onError} has elapsed.
+     * @hide
+     */
+    public static final int ERROR_SERVER_UNAVAILABLE = 13;
+
     /**@hide*/
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "ERROR_", value = {
@@ -145,7 +162,8 @@
             ERROR_REQUEST_TOO_LARGE,
             ERROR_REQUEST_TIMEOUT,
             ERROR_INSUFFICIENT_MEMORY,
-            ERROR_LOST_NETWORK
+            ERROR_LOST_NETWORK,
+            ERROR_SERVER_UNAVAILABLE
     })
     public @interface ErrorCode {}
 
@@ -369,8 +387,10 @@
          * The pending request has resulted in an error and may need to be retried, depending on the
          * error code.
          * @param errorCode The reason for the framework being unable to process the request.
+         * @param retryAfterMilliseconds The time in milliseconds the requesting application should
+         * wait before retrying, if non-zero.
          */
-        void onError(@ErrorCode int errorCode);
+        void onError(@ErrorCode int errorCode, long retryAfterMilliseconds);
     }
 
     private final Context mContext;
@@ -451,10 +471,10 @@
                 }
             }
             @Override
-            public void onError(int errorCode) {
+            public void onError(int errorCode, long retryAfterMilliseconds) {
                 final long callingIdentity = Binder.clearCallingIdentity();
                 try {
-                    executor.execute(() -> c.onError(errorCode));
+                    executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds));
                 } finally {
                     restoreCallingIdentity(callingIdentity);
                 }
@@ -535,10 +555,10 @@
                 }
             }
             @Override
-            public void onError(int errorCode) {
+            public void onError(int errorCode, long retryAfterMilliseconds) {
                 final long callingIdentity = Binder.clearCallingIdentity();
                 try {
-                    executor.execute(() -> c.onError(errorCode));
+                    executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds));
                 } finally {
                     restoreCallingIdentity(callingIdentity);
                 }
diff --git a/telephony/java/android/telephony/ims/SipDelegateConnection.java b/telephony/java/android/telephony/ims/SipDelegateConnection.java
index 6bfdc2c..c3cc1ed 100644
--- a/telephony/java/android/telephony/ims/SipDelegateConnection.java
+++ b/telephony/java/android/telephony/ims/SipDelegateConnection.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.telephony.ims.stub.SipDelegate;
 
 /**
@@ -36,6 +37,7 @@
  * @see SipDelegateManager#createSipDelegate
  * @hide
  */
+@SystemApi
 public interface SipDelegateConnection {
 
     /**
@@ -47,9 +49,8 @@
      * @param sipMessage The SipMessage to be sent.
      * @param configVersion The SipDelegateImsConfiguration version used to construct the
      *                      SipMessage. See {@link SipDelegateImsConfiguration#getVersion} for more
-     *                      information on this parameter and why it is used.
      */
-    void sendMessage(@NonNull SipMessage sipMessage, int configVersion);
+    void sendMessage(@NonNull SipMessage sipMessage, long configVersion);
 
     /**
      * Notify the {@link SipDelegate} that a SIP message received from
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
index 8abd0ee..eddbb10 100644
--- a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
@@ -17,7 +17,10 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.StringDef;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -47,7 +50,8 @@
  * update.
  * @hide
  */
-public class SipDelegateImsConfiguration implements Parcelable {
+@SystemApi
+public final class SipDelegateImsConfiguration implements Parcelable {
 
     /**
      * IPV4 Address type.
@@ -354,7 +358,7 @@
     /**
      * Builder class to be used when constructing a new SipDelegateImsConfiguration.
      */
-    public static class Builder {
+    public static final class Builder {
         private final long mVersion;
         private final PersistableBundle mBundle;
 
@@ -381,7 +385,10 @@
         /**
          * Put a string value into this configuration bundle for the given key.
          */
-        public Builder putString(@StringConfigKey String key, String value) {
+        // getString is available below.
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public @NonNull Builder addString(@NonNull @StringConfigKey String key,
+                @NonNull String value) {
             mBundle.putString(key, value);
             return this;
         }
@@ -389,7 +396,9 @@
         /**
          * Replace the existing default value with a new value for a given key.
          */
-        public Builder putInt(@IntConfigKey String key, int value) {
+        // getInt is available below.
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public @NonNull Builder addInt(@NonNull @IntConfigKey String key, int value) {
             mBundle.putInt(key, value);
             return this;
         }
@@ -397,7 +406,9 @@
         /**
          * Replace the existing default value with a new value for a given key.
          */
-        public Builder putBoolean(@BooleanConfigKey String key, boolean value) {
+        // getBoolean is available below.
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public @NonNull Builder addBoolean(@NonNull @BooleanConfigKey String key, boolean value) {
             mBundle.putBoolean(key, value);
             return this;
         }
@@ -405,7 +416,7 @@
         /**
          * @return a new SipDelegateImsConfiguration from this Builder.
          */
-        public SipDelegateImsConfiguration build() {
+        public @NonNull SipDelegateImsConfiguration build() {
             return new SipDelegateImsConfiguration(mVersion, mBundle);
         }
     }
@@ -424,30 +435,38 @@
     }
 
     /**
+     * @return {@code true} if this configuration object has a an entry for the key specified,
+     * {@code false} if it does not.
+     */
+    public boolean containsKey(@NonNull String key) {
+        return mBundle.containsKey(key);
+    }
+
+    /**
      * @return the string value associated with a given key or {@code null} if it doesn't exist.
      */
-    public @StringConfigKey String getString(String key) {
+    public @Nullable @StringConfigKey String getString(@NonNull String key) {
         return mBundle.getString(key);
     }
 
     /**
-     * @return the Integer value associated with a given key or {@code null} if the value doesn't
-     * exist.
+     * @return the integer value associated with a given key if it exists or the supplied default
+     * value if it does not.
      */
-    public @IntConfigKey Integer getInt(String key) {
+    public @IntConfigKey int getInt(@NonNull String key, int defaultValue) {
         if (!mBundle.containsKey(key)) {
-            return null;
+            return defaultValue;
         }
         return mBundle.getInt(key);
     }
 
     /**
-     * @return the Integer value associated with a given key or {@code null} if the value doesn't
-     * exist.
+     * @return the boolean value associated with a given key or the supplied default value if the
+     * value doesn't exist in the bundle.
      */
-    public @BooleanConfigKey Boolean getBoolen(String key) {
+    public @BooleanConfigKey boolean getBoolean(@NonNull String key, boolean defaultValue) {
         if (!mBundle.containsKey(key)) {
-            return null;
+            return defaultValue;
         }
         return mBundle.getBoolean(key);
     }
@@ -455,7 +474,7 @@
     /**
      * @return a shallow copy of the full configuration.
      */
-    public PersistableBundle copyBundle() {
+    public @NonNull PersistableBundle copyBundle() {
         return new PersistableBundle(mBundle);
     }
 
@@ -479,12 +498,12 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeLong(mVersion);
         dest.writePersistableBundle(mBundle);
     }
 
-    public static final Creator<SipDelegateImsConfiguration> CREATOR =
+    public static final @NonNull Creator<SipDelegateImsConfiguration> CREATOR =
             new Creator<SipDelegateImsConfiguration>() {
         @Override
         public SipDelegateImsConfiguration createFromParcel(Parcel source) {
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index 190a792..2ec88ff 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -54,7 +54,6 @@
      * The SIP message has failed being sent or received for an unknown reason.
      * <p>
      * The caller should retry a message that failed with this response.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_UNKNOWN = 0;
 
@@ -64,47 +63,40 @@
      * <p>
      * This is considered a permanent error and the system will automatically begin the teardown and
      * destruction of the SipDelegate. No further messages should be sent on this transport.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_DELEGATE_DEAD = 1;
 
     /**
      * The message has not been sent/received because the delegate is in the process of closing and
      * has become unavailable. No further messages should be sent/received on this delegate.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2;
 
     /**
      * The SIP message has an invalid start line and the message can not be sent.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3;
 
     /**
      * One or more of the header fields in the header section of the outgoing SIP message is invalid
      * and the SIP message can not be sent.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4;
 
     /**
      * The body content of the SIP message is invalid and the message can not be sent.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT = 5;
 
     /**
      * The feature tag associated with the outgoing message does not match any known feature tags
      * and this message can not be sent.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6;
 
     /**
      * The feature tag associated with the outgoing message is not enabled for the associated
      * SipDelegateConnection and can not be sent.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE = 7;
 
@@ -113,7 +105,6 @@
      * <p>
      * This message should be retried when connectivity to the network is re-established. See
      * {@link android.net.ConnectivityManager.NetworkCallback} for how this can be determined.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE = 8;
 
@@ -124,7 +115,6 @@
      * This is considered a temporary failure, the message should not be retried until an IMS
      * registration change callback is received via
      * {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged}
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_NOT_REGISTERED = 9;
 
@@ -135,7 +125,6 @@
      * <p>
      * The @link SipMessage} should be recreated using the newest
      * {@link SipDelegateImsConfiguration} and sent again.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION = 10;
 
@@ -146,7 +135,6 @@
      * This is considered a temporary error and the {@link SipDelegateConnection} should resend the
      * message once {@link DelegateRegistrationState#DEREGISTERING_REASON_FEATURE_TAGS_CHANGING} is
      * no longer reported.
-     * @hide
      */
     public static final int MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION = 11;
 
@@ -171,7 +159,6 @@
 
     /**
      * Access to use this feature tag has been denied for an unknown reason.
-     * @hide
      */
     public static final int DENIED_REASON_UNKNOWN = 0;
 
@@ -179,14 +166,12 @@
      * This feature tag is allowed to be used by this SipDelegateConnection, but it is in use by
      * another SipDelegateConnection and can not be associated with this delegate. The feature tag
      * will stay in this state until the feature tag is release by the other application.
-     * @hide
      */
     public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1;
 
     /**
      * Access to use this feature tag has been denied because this application does not have the
      * permissions required to access this feature tag.
-     * @hide
      */
     public static final int DENIED_REASON_NOT_ALLOWED = 2;
 
@@ -194,14 +179,12 @@
      * Access to use this feature tag has been denied because single registration is not allowed by
      * the carrier at this time. The application should fall back to dual registration if
      * applicable.
-     * @hide
      */
     public static final int DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED = 3;
 
     /**
      * This feature tag is not recognized as a valid feature tag by the SipDelegate and has been
      * denied.
-     * @hide
      */
     public static final int DENIED_REASON_INVALID = 4;
 
@@ -218,33 +201,28 @@
 
     /**
      * The SipDelegate has closed due to an unknown reason.
-     * @hide
      */
     public static final int SIP_DELEGATE_DESTROY_REASON_UNKNOWN = 0;
 
     /**
      * The SipDelegate has closed because the IMS service has died unexpectedly.
-     * @hide
      */
     public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD = 1;
 
     /**
      * The SipDelegate has closed because the IMS application has requested that the connection be
      * destroyed.
-     * @hide
      */
     public static final int SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP = 2;
 
     /**
      * The SipDelegate has been closed due to the user disabling RCS.
-     * @hide
      */
     public static final int SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS = 3;
 
     /**
      * The SipDelegate has been closed due to the subscription associated with this delegate being
      * torn down.
-     * @hide
      */
     public static final int SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN = 4;
 
@@ -331,7 +309,6 @@
      *           SipDelegateConnection.
      * @throws ImsException Thrown if there was a problem communicating with the ImsService
      * associated with this SipDelegateManager. See {@link ImsException#getCode()}.
-     * @hide
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void createSipDelegate(@NonNull DelegateRequest request, @NonNull Executor executor,
@@ -366,7 +343,6 @@
      * This will also clean up all related callbacks in the associated ImsService.
      * @param delegateConnection The SipDelegateConnection to destroy.
      * @param reason The reason for why this SipDelegateConnection was destroyed.
-     * @hide
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void destroySipDelegate(@NonNull SipDelegateConnection delegateConnection,
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index c3b1be2..1539224 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -17,10 +17,14 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Arrays;
+import java.util.Objects;
+
 /**
  * Represents a partially encoded SIP message. See RFC 3261 for more information on how SIP
  * messages are structured and used.
@@ -29,6 +33,7 @@
  * verification and should not be used as a generic SIP message container.
  * @hide
  */
+@SystemApi
 public final class SipMessage implements Parcelable {
     // Should not be set to true for production!
     private static final boolean IS_DEBUGGING = Build.IS_ENG;
@@ -95,14 +100,14 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mStartLine);
         dest.writeString(mHeaderSection);
         dest.writeInt(mContent.length);
         dest.writeByteArray(mContent);
     }
 
-    public static final Creator<SipMessage> CREATOR = new Creator<SipMessage>() {
+    public static final @NonNull Creator<SipMessage> CREATOR = new Creator<SipMessage>() {
         @Override
         public SipMessage createFromParcel(Parcel source) {
             return new SipMessage(source);
@@ -152,4 +157,21 @@
         }
         return startLine;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        SipMessage that = (SipMessage) o;
+        return mStartLine.equals(that.mStartLine)
+                && mHeaderSection.equals(that.mHeaderSection)
+                && Arrays.equals(mContent, that.mContent);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(mStartLine, mHeaderSection);
+        result = 31 * result + Arrays.hashCode(mContent);
+        return result;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
index 0bd3e5e..0f627b9 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
@@ -26,5 +26,5 @@
 oneway interface IRcsUceControllerCallback {
     void onCapabilitiesReceived(in List<RcsContactUceCapability> contactCapabilities);
     void onComplete();
-    void onError(int errorCode);
+    void onError(int errorCode, long retryAfterMilliseconds);
 }
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
index 477ee95..5d6766a6 100644
--- a/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
@@ -23,7 +23,7 @@
  * {@hide}
  */
 oneway interface ISipDelegate {
-    void sendMessage(in SipMessage sipMessage, int configVersion);
+    void sendMessage(in SipMessage sipMessage, long configVersion);
     void notifyMessageReceived(in String viaTransactionId);
     void notifyMessageReceiveError(in String viaTransactionId, int reason);
 
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index a7f62cc..522ad81 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -29,12 +29,13 @@
 import android.telephony.ims.SipMessage;
 import android.telephony.ims.stub.SipDelegate;
 
-import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
  * Implementation of callbacks by wrapping the internal AIDL from telephony. Also implements
- * ISipDelegate internally when {@link DelegateStateCallback#onCreated(SipDelegate, List)} is called
+ * ISipDelegate internally when {@link DelegateStateCallback#onCreated(SipDelegate, Set)} is called
  * in order to trampoline events back to telephony.
  * @hide
  */
@@ -42,7 +43,7 @@
 
     private final ISipDelegate.Stub mDelegateBinder = new ISipDelegate.Stub() {
         @Override
-        public void sendMessage(SipMessage sipMessage, int configVersion) {
+        public void sendMessage(SipMessage sipMessage, long configVersion) {
             SipDelegate d = mDelegate;
             final long token = Binder.clearCallingIdentity();
             try {
@@ -136,10 +137,10 @@
 
     @Override
     public void onCreated(@NonNull SipDelegate delegate,
-            @Nullable List<FeatureTagState> deniedTags) {
+            @Nullable Set<FeatureTagState> deniedTags) {
         mDelegate = delegate;
         try {
-            mStateBinder.onCreated(mDelegateBinder, deniedTags);
+            mStateBinder.onCreated(mDelegateBinder, new ArrayList<>(deniedTags));
         } catch (RemoteException e) {
             // BinderDied will trigger destroySipDelegate, so just ignore this locally.
         }
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index 3bd1a46..29ba8e2 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -158,7 +158,7 @@
     }
 
     @Override
-    public void sendMessage(SipMessage sipMessage, int configVersion) {
+    public void sendMessage(SipMessage sipMessage, long configVersion) {
         try {
             ISipDelegate conn = getSipDelegateBinder();
             if (conn == null) {
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
index 59f9601..eefe849 100644
--- a/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
@@ -17,6 +17,7 @@
 package android.telephony.ims.stub;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.telephony.ims.SipDelegateConnection;
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.SipMessage;
@@ -26,6 +27,7 @@
  * messages as well as the result of sending a SIP message.
  * @hide
  */
+@SystemApi
 public interface DelegateConnectionMessageCallback {
 
     /**
@@ -49,6 +51,6 @@
      *                         previously sent {@link SipMessage}.
      * @param reason The reason for the failure.
      */
-    void onMessageSendFailure(String viaTransactionId,
+    void onMessageSendFailure(@NonNull String viaTransactionId,
             @SipDelegateManager.MessageFailureReason int reason);
 }
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
index 9761805..02218ea 100644
--- a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
@@ -17,6 +17,7 @@
 package android.telephony.ims.stub;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.telephony.ims.DelegateRegistrationState;
 import android.telephony.ims.DelegateRequest;
 import android.telephony.ims.FeatureTagState;
@@ -58,6 +59,7 @@
  *
  * @hide
  */
+@SystemApi
 public interface DelegateConnectionStateCallback {
 
     /**
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index a6f5c45..153d687 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -49,8 +49,7 @@
      * @hide
      */
     // Defines the underlying radio technology type that we have registered for IMS over.
-    @IntDef(flag = true,
-            value = {
+    @IntDef(value = {
                     REGISTRATION_TECH_NONE,
                     REGISTRATION_TECH_LTE,
                     REGISTRATION_TECH_IWLAN
diff --git a/telephony/java/android/telephony/ims/stub/SipDelegate.java b/telephony/java/android/telephony/ims/stub/SipDelegate.java
index 3ec9709..d7e7b62 100644
--- a/telephony/java/android/telephony/ims/stub/SipDelegate.java
+++ b/telephony/java/android/telephony/ims/stub/SipDelegate.java
@@ -17,6 +17,7 @@
 package android.telephony.ims.stub;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.telephony.ims.DelegateMessageCallback;
 import android.telephony.ims.ImsService;
 import android.telephony.ims.SipDelegateImsConfiguration;
@@ -40,6 +41,7 @@
  * {@link android.telephony.ims.DelegateStateCallback} for more information.
  * @hide
  */
+@SystemApi
 public interface SipDelegate {
 
     /**
@@ -57,7 +59,7 @@
      *         {@link DelegateMessageCallback#onMessageSendFailure} should be called with code
      *         {@link SipDelegateManager#MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION}.
      */
-    void sendMessage(@NonNull SipMessage message, int configVersion);
+    void sendMessage(@NonNull SipMessage message, long configVersion);
 
     /**
      * The framework is requesting that routing resources associated with the SIP dialog using the
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index 93d438c..1f74c09 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -17,6 +17,7 @@
 package android.telephony.ims.stub;
 
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.IBinder;
@@ -32,7 +33,6 @@
 import android.util.Log;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
@@ -99,7 +99,8 @@
     /**
      * Called by the Telephony framework to request the creation of a new {@link SipDelegate}.
      * <p>
-     * The implementation must call {@link DelegateStateCallback#onCreated(SipDelegate, List)} with
+     * The implementation must call
+     * {@link DelegateStateCallback#onCreated(SipDelegate, java.util.Set)} with
      * the {@link SipDelegate} that is associated with the {@link DelegateRequest}.
      * <p>
      * This method will be called on the Executor specified in
@@ -112,8 +113,9 @@
      *           for the SipDelegate.
      * @param mc A callback back to the remote application to be used to send SIP messages to the
      *           remote application and acknowledge the sending of outgoing SIP messages.
-     * @hide
      */
+    // executor used is defined in the constructor.
+    @SuppressLint("ExecutorRegistration")
     public void createSipDelegate(int subscriptionId, @NonNull DelegateRequest request,
             @NonNull DelegateStateCallback dc, @NonNull DelegateMessageCallback mc) {
         throw new UnsupportedOperationException("createSipDelegate not implemented!");
@@ -130,7 +132,6 @@
      * @param delegate The delegate to be destroyed.
      * @param reason The reason the remote connection to this {@link SipDelegate} is being
      *         destroyed.
-     * @hide
      */
     public void destroySipDelegate(@NonNull SipDelegate delegate,
             @SipDelegateManager.SipDelegateDestroyReason int reason) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index b524549..5d4fdd0 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -857,6 +857,11 @@
             in int[] featureTypes, in String packageName);
 
     /**
+     *  @return true if the ImsService cleared any carrier ImsService overrides, false otherwise.
+     */
+    boolean clearCarrierImsServiceOverride(int slotIndex);
+
+    /**
     * @return the package name of the carrier/device ImsService associated with this slot.
     */
     String getBoundImsServicePackage(int slotIndex, boolean isCarrierImsService, int featureType);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index d216162..b905212 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -321,4 +321,107 @@
      */
     public static final String ACTION_USER_ACTIVITY_NOTIFICATION =
             "android.intent.action.USER_ACTIVITY_NOTIFICATION";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#ACTION_CARRIER_SIGNAL_REDIRECTED
+     */
+    @Deprecated
+    public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
+            "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     */
+    @Deprecated
+    public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
+            "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#ACTION_CARRIER_SIGNAL_PCO_VALUE
+     */
+    @Deprecated
+    public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
+            "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE
+     */
+    @Deprecated
+    public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE =
+            "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#ACTION_CARRIER_SIGNAL_RESET
+     */
+    @Deprecated
+    public static final String ACTION_CARRIER_SIGNAL_RESET =
+            "com.android.internal.telephony.CARRIER_SIGNAL_RESET";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_REDIRECTION_URL
+     */
+    @Deprecated
+    public static final String EXTRA_REDIRECTION_URL = "redirectionUrl";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_DATA_FAIL_CAUSE
+     */
+    @Deprecated
+    public static final String EXTRA_ERROR_CODE = "errorCode";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_APN_TYPE
+     */
+    @Deprecated
+    public static final String EXTRA_APN_TYPE = "apnType";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_APN_TYPE
+     */
+    @Deprecated
+    public static final String EXTRA_APN_TYPE_INT = "apnTypeInt";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_APN_PROTOCOL
+     */
+    @Deprecated
+    public static final String EXTRA_APN_PROTOCOL = "apnProto";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_APN_PROTOCOL
+     */
+    @Deprecated
+    public static final String EXTRA_APN_PROTOCOL_INT = "apnProtoInt";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_PCO_ID
+     */
+    @Deprecated
+    public static final String EXTRA_PCO_ID = "pcoId";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_PCO_VALUE
+     */
+    @Deprecated
+    public static final String EXTRA_PCO_VALUE = "pcoValue";
+
+    /**
+     * Kept for backwards compatibility.
+     * @deprecated @see TelephonyManager#EXTRA_DEFAULT_NETWORK_AVAILABLE
+     */
+    @Deprecated
+    public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable";
 }
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 3b9bec9..1a83655 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -59,7 +59,10 @@
 java_library {
     name: "wm-flicker-common-assertions",
     platform_apis: true,
-    srcs: ["src/**/*Assertions.java", "src/**/*Assertions.kt"],
+    srcs: [
+        "src/**/*Assertions.java",
+        "src/**/*Assertions.kt",
+    ],
     exclude_srcs: [
         "**/helpers/*",
     ],
@@ -68,4 +71,17 @@
         "truth-prebuilt",
         "app-helpers-core"
     ],
+}
+
+java_library {
+    name: "wm-flicker-common-app-helpers",
+    platform_apis: true,
+    srcs: [
+        "**/helpers/*"
+    ],
+    static_libs: [
+        "flickerlib",
+        "truth-prebuilt",
+        "app-helpers-core"
+    ],
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
deleted file mode 100644
index 0572a78..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers
-
-import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
-import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
-import org.junit.Assert
-
-class PipAppHelper(
-    instr: Instrumentation,
-    launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
-            .getInstance(instr)
-            .launcherStrategy
-) : StandardAppHelper(instr, "PipApp", launcherStrategy) {
-    fun clickEnterPipButton(device: UiDevice) {
-        val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
-        Assert.assertNotNull("Pip button not found, this usually happens when the device " +
-                "was left in an unknown state (e.g. in split screen)", enterPipButton)
-        enterPipButton.click()
-        device.hasPipWindow()
-    }
-
-    fun closePipWindow(device: UiDevice) {
-        device.closePipWindow()
-    }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 1f03c4d..686ddcb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -105,8 +105,7 @@
                                 configuration.endRotation)
                             navBarLayerIsAlwaysVisible(enabled = false)
                             statusBarLayerIsAlwaysVisible(enabled = false)
-                            visibleLayersShownMoreThanOneConsecutiveEntry(
-                                    enabled = Surface.ROTATION_0 == configuration.endRotation)
+                            visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 174541970)
 
                             appLayerReplacesWallpaperLayer(testApp)
                         }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
deleted file mode 100644
index 89539fd..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.pip
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.Flicker
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.helpers.PipAppHelper
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.closePipWindow
-import com.android.server.wm.flicker.helpers.expandPipWindow
-import com.android.server.wm.flicker.helpers.hasPipWindow
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip launch.
- * To run this test: `atest FlickerTests:PipToAppTest`
- */
-@Presubmit
-@RequiresDevice
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 152738416)
-class EnterPipTest(
-    testName: String,
-    flickerSpec: Flicker
-) : FlickerTestRunner(testName, flickerSpec) {
-    companion object {
-        @Parameterized.Parameters(name = "{0}")
-        @JvmStatic
-        fun getParams(): List<Array<Any>> {
-            val instrumentation = InstrumentationRegistry.getInstrumentation()
-            val testApp = PipAppHelper(instrumentation)
-            return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
-                .buildTest { configuration ->
-                    withTestName { buildTestTag("enterPip", testApp, configuration) }
-                    repeat { configuration.repetitions }
-                    setup {
-                        test {
-                            device.wakeUpAndGoToHomeScreen()
-                        }
-                        eachRun {
-                            device.pressHome()
-                            testApp.open()
-                            this.setRotation(configuration.startRotation)
-                        }
-                    }
-                    teardown {
-                        eachRun {
-                            if (device.hasPipWindow()) {
-                                device.closePipWindow()
-                            }
-                            testApp.exit()
-                            this.setRotation(Surface.ROTATION_0)
-                        }
-                        test {
-                            if (device.hasPipWindow()) {
-                                device.closePipWindow()
-                            }
-                        }
-                    }
-                    transitions {
-                        testApp.clickEnterPipButton(device)
-                        device.expandPipWindow()
-                    }
-                    assertions {
-                        windowManagerTrace {
-                            navBarWindowIsAlwaysVisible()
-                            statusBarWindowIsAlwaysVisible()
-
-                            all("pipWindowBecomesVisible") {
-                                this.showsAppWindow(testApp.`package`)
-                                    .then()
-                                    .showsAppWindow(PIP_WINDOW_TITLE)
-                            }
-                        }
-
-                        layersTrace {
-                            navBarLayerIsAlwaysVisible(bugId = 140855415)
-                            statusBarLayerIsAlwaysVisible()
-                            noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0,
-                                enabled = false)
-                            navBarLayerRotatesAndScales(configuration.startRotation,
-                                Surface.ROTATION_0, bugId = 140855415)
-                            statusBarLayerRotatesScales(configuration.startRotation,
-                                Surface.ROTATION_0)
-                        }
-
-                        layersTrace {
-                            all("pipLayerBecomesVisible") {
-                                this.showsLayer(testApp.launcherName)
-                                    .then()
-                                    .showsLayer(PIP_WINDOW_TITLE)
-                            }
-                        }
-                    }
-                }
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 4d21440..1599ed4 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -49,18 +49,6 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
-        <activity android:name=".PipActivity"
-             android:resizeableActivity="true"
-             android:supportsPictureInPicture="true"
-             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
-             android:taskAffinity="com.android.server.wm.flicker.testapp.PipActivity"
-             android:label="PipApp"
-             android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
         <activity android:name=".SeamlessRotationActivity"
              android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
              android:configChanges="orientation|screenSize"
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index fa0574a5..9738e58 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1064,6 +1064,31 @@
     }
 
     /**
+     * Ensure that the correct mitigation counts are sent to the boot loop observer.
+     */
+    @Test
+    public void testMultipleBootLoopMitigation() {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
+        watchdog.registerHealthObserver(bootObserver);
+        for (int i = 0; i < 4; i++) {
+            for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+                watchdog.noteBoot();
+            }
+        }
+
+        moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+        for (int i = 0; i < 4; i++) {
+            for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+                watchdog.noteBoot();
+            }
+        }
+
+        assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+    }
+
+    /**
      * Ensure that passing a null list of failed packages does not cause any mitigation logic to
      * execute.
      */
@@ -1267,6 +1292,7 @@
         final List<String> mHealthCheckFailedPackages = new ArrayList<>();
         final List<String> mMitigatedPackages = new ArrayList<>();
         final List<Integer> mMitigationCounts = new ArrayList<>();
+        final List<Integer> mBootMitigationCounts = new ArrayList<>();
 
         TestObserver(String name) {
             mName = name;
@@ -1304,12 +1330,13 @@
             return mMayObservePackages;
         }
 
-        public int onBootLoop() {
+        public int onBootLoop(int level) {
             return mImpact;
         }
 
-        public boolean executeBootLoopMitigation() {
+        public boolean executeBootLoopMitigation(int level) {
             mMitigatedBootLoop = true;
+            mBootMitigationCounts.add(level);
             return true;
         }
 
diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
index 9274da2..590105b 100644
--- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
@@ -19,8 +19,6 @@
 
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
-        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
-                  android:exported="true" />
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 52718be..3d8deb5 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -34,7 +34,6 @@
 
 import com.android.cts.install.lib.Install;
 import com.android.cts.install.lib.InstallUtils;
-import com.android.cts.install.lib.LocalIntentSender;
 import com.android.cts.install.lib.TestApp;
 import com.android.cts.install.lib.Uninstall;
 import com.android.cts.rollback.lib.Rollback;
@@ -258,10 +257,6 @@
                 .getPackageManager().getPackageInstaller();
         pi.abandonSession(sessionId);
 
-        // Remove the first intent sender result, so that the next staged install session does not
-        // erroneously think that it has itself been abandoned.
-        // TODO(b/136260017): Restructure LocalIntentSender to negate the need for this step.
-        LocalIntentSender.getIntentSenderResult();
         Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
     }
 
diff --git a/tests/StagedInstallTest/app/AndroidManifest.xml b/tests/StagedInstallTest/app/AndroidManifest.xml
index a678f1ec..d7ac9d0 100644
--- a/tests/StagedInstallTest/app/AndroidManifest.xml
+++ b/tests/StagedInstallTest/app/AndroidManifest.xml
@@ -20,8 +20,6 @@
 
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
-        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
-                  android:exported="true" />
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
index a67156a..a5e44d5 100644
--- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
+++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
@@ -53,8 +53,13 @@
         assertParcelSane(MatchAllNetworkSpecifier(), 0)
     }
 
-    @Test @IgnoreAfter(Build.VERSION_CODES.R)
-    fun testCanBeSatisfiedBy_BeforeS() {
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    @IgnoreAfter(Build.VERSION_CODES.R)
+    // Only run this test on Android R.
+    // The method - satisfiedBy() has changed to canBeSatisfiedBy() starting from Android R, so the
+    // method - canBeSatisfiedBy() cannot be found when running this test on Android Q.
+    fun testCanBeSatisfiedBy_OnlyForR() {
         // MatchAllNetworkSpecifier didn't follow its parent class to change the satisfiedBy() to
         // canBeSatisfiedBy(), so if a caller calls MatchAllNetworkSpecifier#canBeSatisfiedBy(), the
         // NetworkSpecifier#canBeSatisfiedBy() will be called actually, and false will be returned.
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
index b77ed6a..cade5ba 100644
--- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -22,10 +22,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.os.Build;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -34,7 +37,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(AndroidJUnit4.class)
+@IgnoreUpTo(Build.VERSION_CODES.R)
+@RunWith(DevSdkIgnoreRunner.class)
 @SmallTest
 public class OemNetworkPreferencesTest {
 
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2758f61..ba87dc5 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,6 +18,8 @@
 
 import static android.Manifest.permission.CHANGE_NETWORK_STATE;
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.content.Intent.ACTION_USER_ADDED;
+import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -1056,7 +1058,9 @@
 
         public void setUids(Set<UidRange> uids) {
             mNetworkCapabilities.setUids(uids);
-            updateCapabilitiesInternal(null /* defaultNetwork */, true);
+            if (mAgentRegistered) {
+                mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
+            }
         }
 
         public void setVpnType(int vpnType) {
@@ -1082,11 +1086,15 @@
                 throws Exception {
             if (mAgentRegistered) throw new IllegalStateException("already registered");
             setUids(uids);
-            mConfig.isMetered = isAlwaysMetered;
+            if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
             mInterface = VPN_IFNAME;
             mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
                     mNetworkCapabilities);
             mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
+            verify(mNetworkManagementService, times(1))
+                    .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
+            verify(mNetworkManagementService, never())
+                    .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
             mAgentRegistered = true;
             mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
             mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -1141,28 +1149,6 @@
             mMockNetworkAgent.sendLinkProperties(lp);
         }
 
-        private NetworkCapabilities updateCapabilitiesInternal(Network defaultNetwork,
-                boolean sendToConnectivityService) {
-            if (!mAgentRegistered) return null;
-            super.updateCapabilities(defaultNetwork);
-            // Because super.updateCapabilities will update the capabilities of the agent but
-            // not the mock agent, the mock agent needs to know about them.
-            copyCapabilitiesToNetworkAgent(sendToConnectivityService);
-            return new NetworkCapabilities(mNetworkCapabilities);
-        }
-
-        private void copyCapabilitiesToNetworkAgent(boolean sendToConnectivityService) {
-            if (null != mMockNetworkAgent) {
-                mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
-                        sendToConnectivityService);
-            }
-        }
-
-        @Override
-        public NetworkCapabilities updateCapabilities(Network defaultNetwork) {
-            return updateCapabilitiesInternal(defaultNetwork, false);
-        }
-
         public void disconnect() {
             if (mMockNetworkAgent != null) mMockNetworkAgent.disconnect();
             mAgentRegistered = false;
@@ -4944,8 +4930,6 @@
 
         final Network[] cellAndVpn = new Network[] {
                 mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
-        Network[] cellAndWifi = new Network[] {
-                mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
 
         // A VPN with default (null) underlying networks sets the underlying network's interfaces...
         expectForceUpdateIfaces(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
@@ -4955,10 +4939,13 @@
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+        final Network[] onlyNull = new Network[]{null};
         final Network[] wifiAndVpn = new Network[] {
                 mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
-        cellAndWifi = new Network[] {
+        final Network[] cellAndWifi = new Network[] {
                 mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
+        final Network[] cellNullAndWifi = new Network[] {
+                mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
 
         waitForIdle();
         assertEquals(wifiLp, mService.getActiveLinkProperties());
@@ -4984,6 +4971,13 @@
                 new String[]{MOBILE_IFNAME, WIFI_IFNAME});
         reset(mStatsService);
 
+        // Null underlying networks are ignored.
+        mService.setUnderlyingNetworksForVpn(cellNullAndWifi);
+        waitForIdle();
+        expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+                new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+        reset(mStatsService);
+
         // If an underlying network disconnects, that interface should no longer be underlying.
         // This doesn't actually work because disconnectAndDestroyNetwork only notifies
         // NetworkStatsService before the underlying network is actually removed. So the underlying
@@ -5018,6 +5012,7 @@
                 argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
                         && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
         mEthernetNetworkAgent.disconnect();
+        waitForIdle();
         reset(mStatsService);
 
         // When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
@@ -5030,6 +5025,25 @@
         waitForIdle();
         expectForceUpdateIfaces(wifiAndVpn, null);
         reset(mStatsService);
+
+        // Specifying only a null underlying network is the same as no networks.
+        mService.setUnderlyingNetworksForVpn(onlyNull);
+        waitForIdle();
+        expectForceUpdateIfaces(wifiAndVpn, null);
+        reset(mStatsService);
+
+        // Specifying networks that are all disconnected is the same as specifying no networks.
+        mService.setUnderlyingNetworksForVpn(onlyCell);
+        waitForIdle();
+        expectForceUpdateIfaces(wifiAndVpn, null);
+        reset(mStatsService);
+
+        // Passing in null again means follow the default network again.
+        mService.setUnderlyingNetworksForVpn(null);
+        waitForIdle();
+        expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+                new String[]{WIFI_IFNAME});
+        reset(mStatsService);
     }
 
     @Test
@@ -5471,6 +5485,7 @@
 
         final Set<UidRange> ranges = uidRangesForUid(uid);
         mMockVpn.registerAgent(ranges);
+        mService.setUnderlyingNetworksForVpn(new Network[0]);
 
         // VPN networks do not satisfy the default request and are automatically validated
         // by NetworkMonitor
@@ -5479,19 +5494,12 @@
         mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
 
         mMockVpn.connect(false);
-        mService.setUnderlyingNetworksForVpn(new Network[0]);
 
-        genericNetworkCallback.expectAvailableCallbacksUnvalidated(mMockVpn);
+        genericNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
         genericNotVpnNetworkCallback.assertNoCallback();
         wifiNetworkCallback.assertNoCallback();
-        vpnNetworkCallback.expectAvailableCallbacksUnvalidated(mMockVpn);
-        defaultCallback.expectAvailableCallbacksUnvalidated(mMockVpn);
-        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
-        genericNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
-        genericNotVpnNetworkCallback.assertNoCallback();
-        vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, nc -> null == nc.getUids());
-        defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
+        vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
         assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         ranges.clear();
@@ -5884,6 +5892,75 @@
     }
 
     @Test
+    public void testVpnRestrictedUsers() throws Exception {
+        // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+                PERMISSION_GRANTED);
+
+        final NetworkRequest request = new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_NOT_VPN)
+                .build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+
+        // Bring up a VPN
+        mMockVpn.establishForMyUid();
+        callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        callback.assertNoCallback();
+
+        final int uid = Process.myUid();
+        NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
+        assertNotNull("nc=" + nc, nc.getUids());
+        assertEquals(nc.getUids(), uidRangesForUid(uid));
+
+        // Set an underlying network and expect to see the VPN transports change.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        callback.expectCapabilitiesThat(mMockVpn, (caps)
+                -> caps.hasTransport(TRANSPORT_VPN)
+                && caps.hasTransport(TRANSPORT_WIFI));
+        callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
+                -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
+
+        // Create a fake restricted profile whose parent is our user ID.
+        final int userId = UserHandle.getUserId(uid);
+        final int restrictedUserId = userId + 1;
+        final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED);
+        info.restrictedProfileParentId = userId;
+        assertTrue(info.isRestricted());
+        when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info);
+        final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+
+        // Send a USER_ADDED broadcast for it.
+        // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
+        final Handler handler = new Handler(mCsHandlerThread.getLooper());
+        handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+
+        // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
+        // restricted user.
+        callback.expectCapabilitiesThat(mMockVpn, (caps)
+                -> caps.getUids().size() == 2
+                && caps.getUids().contains(new UidRange(uid, uid))
+                && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+                && caps.hasTransport(TRANSPORT_VPN)
+                && caps.hasTransport(TRANSPORT_WIFI));
+
+        // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+        final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+        handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
+
+        // Expect that the VPN gains the UID range for the restricted user.
+        callback.expectCapabilitiesThat(mMockVpn, (caps)
+                -> caps.getUids().size() == 1
+                && caps.getUids().contains(new UidRange(uid, uid))
+                && caps.hasTransport(TRANSPORT_VPN)
+                && caps.hasTransport(TRANSPORT_WIFI));
+    }
+
+    @Test
     public void testIsActiveNetworkMeteredOverWifi() throws Exception {
         // Returns true by default when no network is available.
         assertTrue(mCm.isActiveNetworkMetered());
@@ -6829,8 +6906,8 @@
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
 
-        // Connected VPN should have interface rules set up. There are two expected invocations,
-        // one during VPN uid update, one during VPN LinkProperties update
+        // A connected VPN should have interface rules set up. There are two expected invocations,
+        // one during the VPN initial connection, one during the VPN LinkProperties update.
         ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
         verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
         assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
@@ -7345,20 +7422,14 @@
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        // setUp() calls mockVpn() which adds a VPN with the Test Runner's uid. Configure it to be
-        // active
-        final VpnInfo info = new VpnInfo();
-        info.ownerUid = Process.myUid();
-        info.vpnIface = VPN_IFNAME;
-        mMockVpn.setVpnInfo(info);
-
         mMockVpn.establishForMyUid();
-        waitForIdle();
 
+        // Wait for networks to connect and broadcasts to be sent before removing permissions.
+        waitForIdle();
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
 
-
         assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+        waitForIdle();
         assertTrue(
                 "Active VPN permission not applied",
                 mService.checkConnectivityDiagnosticsPermissions(
@@ -7366,6 +7437,7 @@
                         mContext.getOpPackageName()));
 
         assertTrue(mService.setUnderlyingNetworksForVpn(null));
+        waitForIdle();
         assertFalse(
                 "VPN shouldn't receive callback on non-underlying network",
                 mService.checkConnectivityDiagnosticsPermissions(
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 1dcc07c..d0db55f 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -41,6 +41,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
@@ -86,10 +87,10 @@
 import android.os.Bundle;
 import android.os.ConditionVariable;
 import android.os.INetworkManagementService;
-import android.os.Looper;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.test.TestLooper;
 import android.provider.Settings;
 import android.security.Credentials;
 import android.security.KeyStore;
@@ -100,6 +101,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
+import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
 import com.android.server.IpSecService;
@@ -223,6 +225,8 @@
                 .thenReturn(mNotificationManager);
         when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
                 .thenReturn(mConnectivityManager);
+        when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
+                .thenReturn(Context.CONNECTIVITY_SERVICE);
         when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
         when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
                 .thenReturn(Resources.getSystem().getString(
@@ -589,7 +593,7 @@
     }
 
     @Test
-    public void testNotificationShownForAlwaysOnApp() {
+    public void testNotificationShownForAlwaysOnApp() throws Exception {
         final UserHandle userHandle = UserHandle.of(primaryUser.id);
         final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
@@ -619,7 +623,6 @@
 
     @Test
     public void testCapabilities() {
-        final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
 
         final Network mobile = new Network(1);
@@ -1037,7 +1040,7 @@
         when(exception.getErrorType())
                 .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
 
-        final Vpn vpn = startLegacyVpn(mVpnProfile);
+        final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
 
         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
@@ -1048,20 +1051,20 @@
         ikeCb.onClosedExceptionally(exception);
 
         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
-        assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+        assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
     }
 
     @Test
     public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
         when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
                 .thenThrow(new IllegalArgumentException());
-        final Vpn vpn = startLegacyVpn(mVpnProfile);
+        final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
 
         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
         // state
         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
-        assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+        assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
     }
 
     private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
@@ -1100,8 +1103,7 @@
         // a subsequent CL.
     }
 
-    public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
-        final Vpn vpn = createVpn(primaryUser.id);
+    private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
         setMockedUsers(primaryUser);
 
         // Dummy egress interface
@@ -1118,7 +1120,7 @@
 
     @Test
     public void testStartPlatformVpn() throws Exception {
-        startLegacyVpn(mVpnProfile);
+        startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
         // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
         // a subsequent patch.
     }
@@ -1153,7 +1155,7 @@
                     legacyRunnerReady.open();
                     return new Network(102);
                 });
-        final Vpn vpn = startLegacyVpn(profile);
+        final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
         final TestDeps deps = (TestDeps) vpn.mDeps;
         try {
             // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
@@ -1287,8 +1289,13 @@
         doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
         when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
                 .thenReturn(asUserContext);
-        return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
+        final TestLooper testLooper = new TestLooper();
+        final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
                 userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+        verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
+                provider -> provider.getName().contains("VpnNetworkProvider")
+        ));
+        return vpn;
     }
 
     private static void assertBlocked(Vpn vpn, int... uids) {
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index b90e1bb..8cae14a 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -145,7 +145,6 @@
             }
             return when {
                 cliArgs.contains("--hidden-$kebabCase") -> true
-                this == FeatureFlag.BUILD_UPON -> FeatureFlag.BUILDER.hidden
                 else -> false
             }
         }
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 6c6d011..5fc800b 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -5,8 +5,6 @@
 import com.github.javaparser.ast.body.VariableDeclarator
 import com.github.javaparser.ast.expr.AnnotationExpr
 import com.github.javaparser.ast.expr.ArrayInitializerExpr
-import com.github.javaparser.ast.expr.LiteralExpr
-import com.github.javaparser.ast.expr.UnaryExpr
 import java.io.File
 
 
@@ -163,7 +161,12 @@
         return
     }
 
-    +"/** Copy constructor */"
+    +"/**"
+    +" * Copy constructor"
+    if (FeatureFlag.COPY_CONSTRUCTOR.hidden) {
+        +" * @hide"
+    }
+    +" */"
     +GENERATED_MEMBER_HEADER
     "public $ClassName(@$NonNull $ClassName orig)" {
         fields.forEachApply {
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 2e176c3..d9ad649 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.20"
+const val CODEGEN_VERSION = "1.0.22"
 
 const val CANONICAL_BUILDER_CLASS = "Builder"
 const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 18c4054..73eacc0 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -35,7 +35,7 @@
 PACKAGES=$(for t in $TEAMS; do echo $(eval echo \${${t}_PACKAGES}); done)
 RE=$(echo ${PACKAGES} | sed "s/ /|/g")
 git show --name-only --pretty=format: $1 | grep "config/hiddenapi-.*txt" | while read file; do
-    ENTRIES=$(grep -E "^L(${RE})/" <(git show $1:$file))
+    ENTRIES=$(grep -E "^L(${RE})/" || true <(git show $1:$file))
     if [[ -n "${ENTRIES}" ]]; then
       echo -e "\e[1m\e[31m$file $1 contains the following entries\e[0m"
       echo -e "\e[1m\e[31mfor packages that are handled using UnsupportedAppUsage. Please remove\e[0m"
diff --git a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
index 84faeea..4c1fa6e 100644
--- a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
+++ b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
@@ -33,13 +33,12 @@
 import javax.tools.StandardLocation.CLASS_OUTPUT
 import kotlin.collections.set
 
-
 /**
  * The IntDefProcessor is intended to generate a mapping from ints to their respective string
  * identifier for each IntDef for use by Winscope or any other tool which requires such a mapping.
  *
- * The processor will run when building :frameworks-all and dump all the IntDef mappings found the
- * files the make up :frameworks-all as json to outputPath.
+ * The processor will run when building :framework-minus-apex-intdefs and dump all the IntDef
+ * mappings found in the files that make up the build target as json to outputPath.
  */
 class IntDefProcessor : AbstractProcessor() {
     private val outputName = "intDefMapping.json"
@@ -72,8 +71,8 @@
     }
 
     private fun generateIntDefMapping(
-            annotatedElement: TypeElement,
-            annotationType: TypeElement
+        annotatedElement: TypeElement,
+        annotationType: TypeElement
     ): Map<Int, String> {
         // LinkedHashMap makes sure ordering is the same as in the code
         val mapping = LinkedHashMap<Int, String>()
@@ -151,8 +150,8 @@
 
     companion object {
         fun serializeTo(
-                annotationTypeToIntDefMapping: Map<String, IntDefMapping>,
-                writer: Writer
+            annotationTypeToIntDefMapping: Map<String, IntDefMapping>,
+            writer: Writer
         ) {
             val indent = "  "
 
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index fe6ca55..56f4db0 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -20,7 +20,7 @@
 
 #include <map>
 
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+#include "frameworks/proto_logging/stats/atoms.pb.h"
 
 namespace android {
 namespace stats_log_api_gen {
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 5d196c4..b13851c 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -24,7 +24,7 @@
 #include <set>
 #include <vector>
 
-#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h"
+#include "frameworks/proto_logging/stats/atom_field_options.pb.h"
 
 namespace android {
 namespace stats_log_api_gen {
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 2830249..50f81760 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "Collation.h"
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+#include "frameworks/proto_logging/stats/atoms.pb.h"
 #include "java_writer.h"
 #include "java_writer_q.h"
 #include "native_writer.h"
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index e658b62..18c52bf 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -16,8 +16,8 @@
 
 syntax = "proto2";
 
-import "frameworks/base/cmds/statsd/src/atoms.proto";
-import "frameworks/base/cmds/statsd/src/atom_field_options.proto";
+import "frameworks/proto_logging/stats/atoms.proto";
+import "frameworks/proto_logging/stats/atom_field_options.proto";
 
 package android.stats_log_api_gen;
 
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl b/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
similarity index 80%
copy from location/java/android/location/timezone/LocationTimeZoneEvent.aidl
copy to wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
index 5386588..cb359e9 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.aidl
+++ b/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
@@ -1,5 +1,5 @@
-/*
- * Copyright (C) 2020, The Android Open Source Project
+/**
+ * Copyright (c) 2020, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.location.timezone;
+package android.net.wifi;
 
-parcelable LocationTimeZoneEvent;
+parcelable CoexUnsafeChannel;
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 911f2fb..ce2b8ca 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -14,6 +14,7 @@
     field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
     field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
     field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+    field public static final int EASY_CONNECT_EVENT_FAILURE_URI_GENERATION = -13; // 0xfffffff3
   }
 
   public final class ScanResult implements android.os.Parcelable {
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index c4a1766..48d9fd4 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -1,8 +1,20 @@
 // Signature format: 2.0
 package android.net.wifi {
 
+  public final class CoexUnsafeChannel implements android.os.Parcelable {
+    ctor public CoexUnsafeChannel(int, int);
+    ctor public CoexUnsafeChannel(int, int, int);
+    method public int getBand();
+    method public int getChannel();
+    method public int getPowerCapDbm();
+    method public boolean isPowerCapAvailable();
+    method public void setPowerCapDbm(int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.CoexUnsafeChannel> CREATOR;
+  }
+
   public abstract class EasyConnectStatusCallback {
     ctor public EasyConnectStatusCallback();
+    method public void onBootstrapUriGenerated(@NonNull String);
     method public abstract void onConfiguratorSuccess(int);
     method public abstract void onEnrolleeSuccess(int);
     method public void onFailure(int);
@@ -455,6 +467,8 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
+    method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public int getCoexRestrictions();
+    method @NonNull @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public java.util.Set<android.net.wifi.CoexUnsafeChannel> getCoexUnsafeChannels();
     method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
@@ -475,6 +489,7 @@
     method public boolean isVerboseLoggingEnabled();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
+    method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void registerCoexCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.CoexCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
@@ -486,6 +501,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS) public void setCoexUnsafeChannels(@NonNull java.util.Set<android.net.wifi.CoexUnsafeChannel>, int);
     method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int);
@@ -497,6 +513,7 @@
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeResponder(@Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
@@ -505,6 +522,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void stopTemporarilyDisablingAllNonCarrierMergedWifi();
+    method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void unregisterCoexCallback(@NonNull android.net.wifi.WifiManager.CoexCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
@@ -518,11 +536,22 @@
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
     field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
+    field public static final int COEX_RESTRICTION_SOFTAP = 2; // 0x2
+    field public static final int COEX_RESTRICTION_WIFI_AWARE = 4; // 0x4
+    field public static final int COEX_RESTRICTION_WIFI_DIRECT = 1; // 0x1
     field public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
     field public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1; // 0x1
     field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
     field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
     field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3; // 0x3
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4; // 0x4
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5; // 0x5
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT = 0; // 0x0
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0; // 0x0
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1; // 0x1
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2; // 0x2
+    field public static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40; // 0x28
     field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
     field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
     field public static final String EXTRA_CHANGE_REASON = "changeReason";
@@ -565,6 +594,11 @@
     method public void onSuccess();
   }
 
+  public abstract static class WifiManager.CoexCallback {
+    ctor public WifiManager.CoexCallback();
+    method public abstract void onCoexUnsafeChannelsChanged();
+  }
+
   public static interface WifiManager.NetworkRequestMatchCallback {
     method public default void onAbort();
     method public default void onMatch(@NonNull java.util.List<android.net.wifi.ScanResult>);
diff --git a/wifi/java/android/net/wifi/CoexUnsafeChannel.java b/wifi/java/android/net/wifi/CoexUnsafeChannel.java
new file mode 100644
index 0000000..3f9efa0
--- /dev/null
+++ b/wifi/java/android/net/wifi/CoexUnsafeChannel.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
+import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ;
+import static android.net.wifi.WifiScanner.WIFI_BAND_6_GHZ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Data structure class representing a Wi-Fi channel that would cause interference to/receive
+ * interference from the active cellular channels and should be avoided.
+ *
+ * If {@link #isPowerCapAvailable()} is {@code true}, then a valid power cap value is available
+ * through {@link #getPowerCapDbm()} to be used if this channel cannot be avoided. If {@code false},
+ * then {@link #getPowerCapDbm()} throws an IllegalStateException and the channel will not need to
+ * cap its power.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CoexUnsafeChannel implements Parcelable {
+    private @WifiAnnotations.WifiBandBasic int mBand;
+    private int mChannel;
+    private boolean mIsPowerCapAvailable = false;
+    private int mPowerCapDbm;
+
+    /**
+     * Constructor for a CoexUnsafeChannel with no power cap specified.
+     * @param band One of {@link WifiAnnotations.WifiBandBasic}
+     * @param channel Channel number
+     */
+    public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel) {
+        mBand = band;
+        mChannel = channel;
+    }
+
+    /**
+     * Constructor for a CoexUnsafeChannel with power cap specified.
+     * @param band One of {@link WifiAnnotations.WifiBandBasic}
+     * @param channel Channel number
+     * @param powerCapDbm Power cap in dBm
+     */
+    public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel,
+            int powerCapDbm) {
+        mBand = band;
+        mChannel = channel;
+        setPowerCapDbm(powerCapDbm);
+    }
+
+    /** Returns the Wi-Fi band of this channel as one of {@link WifiAnnotations.WifiBandBasic} */
+    public @WifiAnnotations.WifiBandBasic int getBand() {
+        return mBand;
+    }
+
+    /** Returns the channel number of this channel. */
+    public int getChannel() {
+        return mChannel;
+    }
+
+    /** Returns {@code true} if {@link #getPowerCapDbm()} is a valid value, else {@code false} */
+    public boolean isPowerCapAvailable() {
+        return mIsPowerCapAvailable;
+    }
+
+    /**
+     * Returns the power cap of this channel in dBm. Throws IllegalStateException if
+     * {@link #isPowerCapAvailable()} is {@code false}.
+     */
+    public int getPowerCapDbm() {
+        if (!mIsPowerCapAvailable) {
+            throw new IllegalStateException("getPowerCapDbm called but power cap is unavailable");
+        }
+        return mPowerCapDbm;
+    }
+
+    /** Set the power cap of this channel. */
+    public void setPowerCapDbm(int powerCapDbm) {
+        mIsPowerCapAvailable = true;
+        mPowerCapDbm = powerCapDbm;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        CoexUnsafeChannel that = (CoexUnsafeChannel) o;
+        return mBand == that.mBand
+                && mChannel == that.mChannel
+                && mIsPowerCapAvailable == that.mIsPowerCapAvailable
+                && mPowerCapDbm == that.mPowerCapDbm;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mBand, mChannel, mIsPowerCapAvailable, mPowerCapDbm);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sj = new StringBuilder("CoexUnsafeChannel{");
+        sj.append(mChannel);
+        sj.append(", ");
+        if (mBand == WIFI_BAND_24_GHZ) {
+            sj.append("2.4GHz");
+        } else if (mBand == WIFI_BAND_5_GHZ) {
+            sj.append("5GHz");
+        } else if (mBand == WIFI_BAND_6_GHZ) {
+            sj.append("6GHz");
+        } else {
+            sj.append("UNKNOWN BAND");
+        }
+        if (mIsPowerCapAvailable) {
+            sj.append(", ").append(mPowerCapDbm).append("dBm");
+        }
+        sj.append('}');
+        return sj.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mBand);
+        dest.writeInt(mChannel);
+        dest.writeBoolean(mIsPowerCapAvailable);
+        if (mIsPowerCapAvailable) {
+            dest.writeInt(mPowerCapDbm);
+        }
+    }
+
+    /** Implement the Parcelable interface */
+    public static final @NonNull Creator<CoexUnsafeChannel> CREATOR =
+            new Creator<CoexUnsafeChannel>() {
+                public CoexUnsafeChannel createFromParcel(Parcel in) {
+                    final int band = in.readInt();
+                    final int channel = in.readInt();
+                    final boolean isPowerCapAvailable = in.readBoolean();
+                    if (isPowerCapAvailable) {
+                        final int powerCapDbm = in.readInt();
+                        return new CoexUnsafeChannel(band, channel, powerCapDbm);
+                    }
+                    return new CoexUnsafeChannel(band, channel);
+                }
+
+                public CoexUnsafeChannel[] newArray(int size) {
+                    return new CoexUnsafeChannel[size];
+                }
+            };
+}
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
index 6c2e6dd..ee70255 100644
--- a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -161,6 +161,11 @@
      */
     public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12;
 
+    /**
+     * Easy Connect Failure event: System failed to generate DPP URI.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_URI_GENERATION = -13;
+
     /** @hide */
     @IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
             EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
@@ -175,6 +180,7 @@
             EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
             EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION,
             EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION,
+            EASY_CONNECT_EVENT_FAILURE_URI_GENERATION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EasyConnectFailureStatusCode {
@@ -264,4 +270,17 @@
      */
     @SystemApi
     public abstract void onProgress(@EasyConnectProgressStatusCode int code);
+
+    /**
+     * Called when local Easy Connect Responder successfully generates a DPP URI from
+     * the supplicant. This callback is the first successful outcome
+     * of a Easy Connect Responder flow starting with
+     * {@link WifiManager#startEasyConnectAsEnrolleeResponder(String, int, Executor,
+     * EasyConnectStatusCallback)} .
+     *
+     * @param uri DPP URI from the supplicant.
+     * @hide
+     */
+    @SystemApi
+    public void onBootstrapUriGenerated(@NonNull String uri) {};
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt b/wifi/java/android/net/wifi/ICoexCallback.aidl
similarity index 78%
copy from tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
copy to wifi/java/android/net/wifi/ICoexCallback.aidl
index 6bc9dcb..89e4c4b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/CommonAssertions.kt
+++ b/wifi/java/android/net/wifi/ICoexCallback.aidl
@@ -14,6 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.flicker.pip
+package android.net.wifi;
 
-internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
+/**
+ * Interface for Wi-Fi/cellular coex callback.
+ * @hide
+ */
+oneway interface ICoexCallback
+{
+    void onCoexUnsafeChannelsChanged();
+}
diff --git a/wifi/java/android/net/wifi/IDppCallback.aidl b/wifi/java/android/net/wifi/IDppCallback.aidl
index d7a958a..dcbe8468 100644
--- a/wifi/java/android/net/wifi/IDppCallback.aidl
+++ b/wifi/java/android/net/wifi/IDppCallback.aidl
@@ -45,4 +45,10 @@
      * to show progress.
      */
     void onProgress(int status);
+
+    /**
+     * Called when local DPP Responder successfully generates a URI.
+     */
+    void onBootstrapUriGenerated(String uri);
+
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index cc864ea..6dee751 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -24,7 +24,9 @@
 
 import android.net.DhcpInfo;
 import android.net.Network;
+import android.net.wifi.CoexUnsafeChannel;
 import android.net.wifi.IActionListener;
+import android.net.wifi.ICoexCallback;
 import android.net.wifi.IDppCallback;
 import android.net.wifi.ILocalOnlyHotspotCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
@@ -144,6 +146,16 @@
 
     void updateInterfaceIpState(String ifaceName, int mode);
 
+    void setCoexUnsafeChannels(in List<CoexUnsafeChannel> unsafeChannels, int mandatoryRestrictions);
+
+    List<CoexUnsafeChannel> getCoexUnsafeChannels();
+
+    int getCoexRestrictions();
+
+    void registerCoexCallback(in ICoexCallback callback);
+
+    void unregisterCoexCallback(in ICoexCallback callback);
+
     boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName);
 
     boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName);
@@ -235,6 +247,9 @@
     void startDppAsEnrolleeInitiator(in IBinder binder, in String configuratorUri,
         in IDppCallback callback);
 
+    void startDppAsEnrolleeResponder(in IBinder binder, in String deviceInfo, int curve,
+        in IDppCallback callback);
+
     void stopDppSession();
 
     void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec);
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 9f9d7f3..fddc889 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -538,6 +538,15 @@
         if (!SdkLevel.isAtLeastS()) {
             throw new UnsupportedOperationException();
         }
+        return getChannelsInternal();
+    }
+
+    /**
+     * Internal version bypassing SdkLevel checks
+     * TODO(b/173791707): find a better way to allow Wifi to call its own new S APIs.
+     * @hide
+     */
+    public @NonNull SparseIntArray getChannelsInternal() {
         return mChannels.clone();
     }
 
diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java
index 9a16fac..55c2f17 100644
--- a/wifi/java/android/net/wifi/SoftApInfo.java
+++ b/wifi/java/android/net/wifi/SoftApInfo.java
@@ -183,6 +183,15 @@
         if (!SdkLevel.isAtLeastS()) {
             throw new UnsupportedOperationException();
         }
+        return getWifiStandardInternal();
+    }
+
+    /**
+     * Internal version bypassing SdkLevel checks
+     * TODO(b/173791707): find a better way to allow Wifi to call its own new S APIs.
+     * @hide
+     */
+    public @WifiAnnotations.WifiStandard int getWifiStandardInternal() {
         return mWifiStandard;
     }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index da7c9c0..b8fa1e1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -72,6 +72,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -3110,6 +3111,238 @@
         }
     }
 
+    /* Wi-Fi/Cellular Coex */
+
+    /**
+     * Mandatory coex restriction flag for Wi-Fi Direct.
+     *
+     * @see #setCoexUnsafeChannels(Set, int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int COEX_RESTRICTION_WIFI_DIRECT = 0x1 << 0;
+
+    /**
+     * Mandatory coex restriction flag for SoftAP
+     *
+     * @see #setCoexUnsafeChannels(Set, int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int COEX_RESTRICTION_SOFTAP = 0x1 << 1;
+
+    /**
+     * Mandatory coex restriction flag for Wi-Fi Aware.
+     *
+     * @see #setCoexUnsafeChannels(Set, int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int COEX_RESTRICTION_WIFI_AWARE = 0x1 << 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = {"COEX_RESTRICTION_"}, value = {
+            COEX_RESTRICTION_WIFI_DIRECT,
+            COEX_RESTRICTION_SOFTAP,
+            COEX_RESTRICTION_WIFI_AWARE
+    })
+    public @interface CoexRestriction {}
+
+    /**
+     * Specify the set of {@link CoexUnsafeChannel} to propagate through the framework for
+     * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
+     * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
+     *
+     * @param unsafeChannels Set of {@link CoexUnsafeChannel} to avoid.
+     * @param restrictions Bitmap of {@link CoexRestriction} specifying the mandatory restricted
+     *                     uses of the specified channels. If any restrictions are set, then the
+     *                     supplied CoexUnsafeChannels will be completely avoided for the
+     *                     specified modes, rather than be avoided with best effort.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS)
+    public void setCoexUnsafeChannels(@NonNull Set<CoexUnsafeChannel> unsafeChannels,
+            int restrictions) {
+        if (unsafeChannels == null) {
+            throw new IllegalArgumentException("unsafeChannels must not be null");
+        }
+        try {
+            mService.setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the set of current {@link CoexUnsafeChannel} being used for Wi-Fi/Cellular coex
+     * channel avoidance.
+     *
+     * This returns the set calculated by the default algorithm if
+     * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the set supplied
+     * in {@link #setCoexUnsafeChannels(Set, int)}.
+     *
+     * If any {@link CoexRestriction} flags are set in {@link #getCoexRestrictions()}, then the
+     * CoexUnsafeChannels should be totally avoided (i.e. not best effort) for the Wi-Fi modes
+     * specified by the flags.
+     *
+     * @return Set of current CoexUnsafeChannels.
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public Set<CoexUnsafeChannel> getCoexUnsafeChannels() {
+        try {
+            return new HashSet<>(mService.getCoexUnsafeChannels());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the current coex restrictions being used for Wi-Fi/Cellular coex
+     * channel avoidance.
+     *
+     * This returns the restrictions calculated by the default algorithm if
+     * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the value supplied
+     * in {@link #setCoexUnsafeChannels(Set, int)}.
+     *
+     * @return int containing a bitwise-OR combination of {@link CoexRestriction}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public int getCoexRestrictions() {
+        try {
+            return mService.getCoexRestrictions();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers a CoexCallback to listen on the current CoexUnsafeChannels and restrictions being
+     * used for Wi-Fi/cellular coex channel avoidance.
+     * @param executor Executor to execute listener callback on
+     * @param callback CoexCallback to register
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public void registerCoexCallback(
+            @NonNull @CallbackExecutor Executor executor, @NonNull CoexCallback callback) {
+        if (executor == null) throw new IllegalArgumentException("executor must not be null");
+        if (callback == null) throw new IllegalArgumentException("callback must not be null");
+        CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
+        proxy.initProxy(executor, callback);
+        try {
+            mService.registerCoexCallback(proxy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregisters a CoexCallback from listening on the current CoexUnsafeChannels and restrictions
+     * being used for Wi-Fi/cellular coex channel avoidance.
+     * @param callback CoexCallback to unregister
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public void unregisterCoexCallback(@NonNull CoexCallback callback) {
+        if (callback == null) throw new IllegalArgumentException("callback must not be null");
+        CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
+        try {
+            mService.unregisterCoexCallback(proxy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } finally {
+            proxy.cleanUpProxy();
+        }
+    }
+
+    /**
+     * Abstract callback class for applications to receive updates about current CoexUnsafeChannels
+     * for Wi-Fi/Cellular coex channel avoidance.
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract static class CoexCallback {
+        private final CoexCallbackProxy mCoexCallbackProxy;
+
+        public CoexCallback() {
+            mCoexCallbackProxy = new CoexCallbackProxy();
+        }
+
+        /*package*/ @NonNull
+        CoexCallbackProxy getProxy() {
+            return mCoexCallbackProxy;
+        }
+
+        /**
+         * Indicates that the current CoexUnsafeChannels or restrictions have changed.
+         * Clients should call {@link #getCoexUnsafeChannels()} and {@link #getCoexRestrictions()}
+         * to get the updated values.
+         */
+        public abstract void onCoexUnsafeChannelsChanged();
+
+        /**
+         * Callback proxy for CoexCallback objects.
+         */
+        private static class CoexCallbackProxy extends ICoexCallback.Stub {
+            private final Object mLock = new Object();
+            @Nullable @GuardedBy("mLock") private Executor mExecutor;
+            @Nullable @GuardedBy("mLock") private CoexCallback mCallback;
+
+            CoexCallbackProxy() {
+                mExecutor = null;
+                mCallback = null;
+            }
+
+            /*package*/ void initProxy(@NonNull Executor executor,
+                    @NonNull CoexCallback callback) {
+                synchronized (mLock) {
+                    mExecutor = executor;
+                    mCallback = callback;
+                }
+            }
+
+            /*package*/ void cleanUpProxy() {
+                synchronized (mLock) {
+                    mExecutor = null;
+                    mCallback = null;
+                }
+            }
+
+            @Override
+            public void onCoexUnsafeChannelsChanged() {
+                Executor executor;
+                CoexCallback callback;
+                synchronized (mLock) {
+                    executor = mExecutor;
+                    callback = mCallback;
+                }
+                if (executor == null || callback == null) {
+                    return;
+                }
+                Binder.clearCallingIdentity();
+                executor.execute(callback::onCoexUnsafeChannelsChanged);
+            }
+        }
+    }
+
     /**
      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
      * Note that starting Soft AP mode may disable station mode operation if the device does not
@@ -5551,6 +5784,89 @@
     }
 
     /**
+     * Easy Connect Device information maximum allowed length.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40;
+
+    /**
+     * Easy Connect Cryptography Curve name: prime256v1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0;
+
+    /**
+     * Easy Connect Cryptography Curve name: secp384r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1;
+
+    /**
+     * Easy Connect Cryptography Curve name: secp521r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2;
+
+
+    /**
+     * Easy Connect Cryptography Curve name: brainpoolP256r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3;
+
+
+    /**
+     * Easy Connect Cryptography Curve name: brainpoolP384r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4;
+
+
+    /**
+     * Easy Connect Cryptography Curve name: brainpoolP512r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5;
+
+    /**
+     * Easy Connect Cryptography Curve name: default
+     * This allows framework to choose manadatory curve prime256v1.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT =
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1;
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_CRYPTOGRAPHY_CURVE_"}, value = {
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectCryptographyCurve {
+    }
+
+    /**
      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
      * the specified network using the Easy Connect protocol on an encrypted link.
@@ -5606,6 +5922,52 @@
     }
 
     /**
+     * Start Easy Connect (DPP) in Enrollee-Responder role.
+     * The device will:
+     * 1. Generate a DPP bootstrap URI and return it using the
+     * {@link EasyConnectStatusCallback#onBootstrapUriGenerated(String)} method.
+     * 2. Start DPP as a Responder, waiting for an Initiator device to start the DPP
+     * authentication process.
+     * The caller should use the URI provided in step #1, for instance display it as a QR code
+     * or communicate it in some other way to the initiator device.
+     *
+     * @param deviceInfo      Device specific information to add to the DPP URI. This field allows
+     *                        the users of the configurators to identify the device.
+     *                        Optional - if not provided or in case of an empty string,
+     *                        Info field (I:) will be skipped in the generated DPP URI.
+     *                        Allowed Range of ASCII characters in deviceInfo - %x20-7E.
+     *                        semicolon and space are not allowed.
+     *                        Due to the limitation of maximum allowed characters in QR code,
+     *                        framework limits to a max of
+     *                        {@link #EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH} characters in
+     *                        deviceInfo.
+     *                        Violation of these rules will result in an exception.
+     * @param curve           Elliptic curve cryptography used to generate DPP
+     *                        public/private key pair. If application is not interested in a
+     *                        specific curve, choose default curve
+     *                        {@link #EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT}.
+     * @param callback        Callback for status updates
+     * @param executor        The Executor on which to run the callback.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startEasyConnectAsEnrolleeResponder(@Nullable String deviceInfo,
+            @EasyConnectCryptographyCurve int curve,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull EasyConnectStatusCallback callback) {
+        Binder binder = new Binder();
+        try {
+            mService.startDppAsEnrolleeResponder(binder, deviceInfo, curve,
+                    new EasyConnectCallbackProxy(executor, callback));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
      * expect any callbacks once this call is made. However, due to the asynchronous nature of
@@ -5679,6 +6041,15 @@
                 mEasyConnectStatusCallback.onProgress(status);
             });
         }
+
+        @Override
+        public void onBootstrapUriGenerated(String uri) {
+            Log.d(TAG, "Easy Connect onBootstrapUriGenerated callback");
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
+                mEasyConnectStatusCallback.onBootstrapUriGenerated(uri);
+            });
+        }
     }
 
     /**
@@ -5853,7 +6224,6 @@
                 executor.execute(callback::onScanResultsAvailable);
             }
         }
-
     }
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java b/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java
new file mode 100644
index 0000000..320f25e
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.CoexUnsafeChannel}.
+ */
+@SmallTest
+public class CoexUnsafeChannelTest {
+    /**
+     * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns false if no cap is set.
+     */
+    @Test
+    public void testIsPowerCapAvailable_noPowerCap_returnsFalse() {
+        CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+        assertThat(unsafeChannel.isPowerCapAvailable()).isFalse();
+    }
+
+    /**
+     * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns true if a cap is set, and
+     * {@link CoexUnsafeChannel#getPowerCapDbm()} returns the set value.
+     */
+    @Test
+    public void testIsPowerCapAvailable_powerCapSet_returnsTrue() {
+        final int powerCapDbm = -50;
+        CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+        unsafeChannel.setPowerCapDbm(powerCapDbm);
+
+        assertThat(unsafeChannel.isPowerCapAvailable()).isTrue();
+        assertThat(unsafeChannel.getPowerCapDbm()).isEqualTo(powerCapDbm);
+    }
+
+    /**
+     * Verifies {@link CoexUnsafeChannel#getPowerCapDbm()} throws an IllegalStateException if
+     * {@link CoexUnsafeChannel#isPowerCapAvailable()} is {@code false}.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testGetPowerCap_powerCapUnavailable_throwsException() {
+        CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+        unsafeChannel.getPowerCapDbm();
+    }
+
+    /**
+     * Verify parcel read/write for CoexUnsafeChannel with or without power cap.
+     */
+    @Test
+    public void testParcelReadWrite_withOrWithoutCap_readEqualsWritten() throws Exception {
+        CoexUnsafeChannel writeUnsafeChannelNoCap =
+                new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+        CoexUnsafeChannel writeUnsafeChannelCapped =
+                new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6, -50);
+
+        CoexUnsafeChannel readUnsafeChannelNoCap = parcelReadWrite(writeUnsafeChannelNoCap);
+        CoexUnsafeChannel readUnsafeChannelCapped = parcelReadWrite(writeUnsafeChannelCapped);
+
+        assertThat(writeUnsafeChannelNoCap).isEqualTo(readUnsafeChannelNoCap);
+        assertThat(writeUnsafeChannelCapped).isEqualTo(readUnsafeChannelCapped);
+    }
+
+    /**
+     * Write the provided {@link CoexUnsafeChannel} to a parcel and deserialize it.
+     */
+    private static CoexUnsafeChannel parcelReadWrite(CoexUnsafeChannel writeResult)
+            throws Exception {
+        Parcel parcel = Parcel.obtain();
+        writeResult.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        return CoexUnsafeChannel.CREATOR.createFromParcel(parcel);
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
index b101414..cf37b78 100644
--- a/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
+++ b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.NonNull;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
@@ -52,6 +53,11 @@
             mOnFailureR1EventReceived = true;
             mLastCode = code;
         }
+
+        @Override
+        public void onBootstrapUriGenerated(@NonNull String uri) {
+
+        }
     };
     private boolean mOnFailureR1EventReceived;
     private int mLastCode;
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index aefebbc..39f6f57 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -19,6 +19,9 @@
 import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED;
 import static android.net.wifi.WifiManager.ActionListener;
 import static android.net.wifi.WifiManager.BUSY;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT;
 import static android.net.wifi.WifiManager.ERROR;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
@@ -43,6 +46,7 @@
 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
 import static android.net.wifi.WifiManager.WpsCallback;
+import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -74,6 +78,7 @@
 import android.content.pm.ApplicationInfo;
 import android.net.DhcpInfo;
 import android.net.MacAddress;
+import android.net.wifi.WifiManager.CoexCallback;
 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
 import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
 import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
@@ -108,9 +113,11 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
@@ -151,6 +158,7 @@
     private WifiManager mWifiManager;
     private WifiNetworkSuggestion mWifiNetworkSuggestion;
     private ScanResultsCallback mScanResultsCallback;
+    private CoexCallback mCoexCallback;
     private WifiActivityEnergyInfo mWifiActivityEnergyInfo;
 
     /**
@@ -214,10 +222,149 @@
                 mRunnable.run();
             }
         };
+        mCoexCallback = new CoexCallback() {
+            @Override
+            public void onCoexUnsafeChannelsChanged() {
+                mRunnable.run();
+            }
+        };
         mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
     }
 
     /**
+     * Check the call to setCoexUnsafeChannels calls WifiServiceImpl to setCoexUnsafeChannels with
+     * the provided CoexUnsafeChannels and restrictions bitmask.
+     */
+    @Test
+    public void testSetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception {
+        Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>();
+        int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP
+                | COEX_RESTRICTION_WIFI_AWARE;
+
+        mWifiManager.setCoexUnsafeChannels(unsafeChannels, restrictions);
+
+        verify(mWifiService).setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions);
+    }
+
+    /**
+     * Verify an IllegalArgumentException if passed a null value for unsafeChannels.
+     */
+    @Test
+    public void testSetCoexUnsafeChannelsThrowsIllegalArgumentExceptionOnNullUnsafeChannels() {
+        try {
+            mWifiManager.setCoexUnsafeChannels(null, 0);
+            fail("expected IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    /**
+     * Check the call to getCoexUnsafeChannels calls WifiServiceImpl to return the values from
+     * getCoexUnsafeChannels.
+     */
+    @Test
+    public void testGetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception {
+        Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>();
+        unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6));
+        when(mWifiService.getCoexUnsafeChannels()).thenReturn(new ArrayList<>(unsafeChannels));
+
+        assertEquals(mWifiManager.getCoexUnsafeChannels(), unsafeChannels);
+    }
+
+    /**
+     * Verify call to getCoexRestrictions calls WifiServiceImpl to return the value from
+     * getCoexRestrictions.
+     */
+    @Test
+    public void testGetCoexRestrictionsGoesToWifiServiceImpl() throws Exception {
+        int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP
+                | COEX_RESTRICTION_WIFI_AWARE;
+        when(mWifiService.getCoexRestrictions()).thenReturn(restrictions);
+
+        assertEquals(mWifiService.getCoexRestrictions(), restrictions);
+    }
+
+
+    /**
+     * Verify an IllegalArgumentException is thrown if callback is not provided.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testRegisterCoexCallbackWithNullCallback() throws Exception {
+        mWifiManager.registerCoexCallback(mExecutor, null);
+    }
+
+    /**
+     * Verify an IllegalArgumentException is thrown if executor is not provided.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testRegisterCoexCallbackWithNullExecutor() throws Exception {
+        mWifiManager.registerCoexCallback(null, mCoexCallback);
+    }
+
+    /**
+     * Verify client provided callback is being called to the right callback.
+     */
+    @Test
+    public void testAddCoexCallbackAndReceiveEvent() throws Exception {
+        ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+        mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+        verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mRunnable).run();
+    }
+
+    /**
+     * Verify client provided callback is being called to the right executor.
+     */
+    @Test
+    public void testRegisterCoexCallbackWithTheTargetExecutor() throws Exception {
+        ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+        mWifiManager.registerCoexCallback(mExecutor, mCoexCallback);
+        verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+        mWifiManager.registerCoexCallback(mAnotherExecutor, mCoexCallback);
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mExecutor, never()).execute(any(Runnable.class));
+        verify(mAnotherExecutor).execute(any(Runnable.class));
+    }
+
+    /**
+     * Verify client register unregister then register again, to ensure callback still works.
+     */
+    @Test
+    public void testRegisterUnregisterThenRegisterAgainWithCoexCallback() throws Exception {
+        ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+        mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+        verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+        mWifiManager.unregisterCoexCallback(mCoexCallback);
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mRunnable, never()).run();
+        mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mRunnable).run();
+    }
+
+    /**
+     * Verify client unregisterCoexCallback.
+     */
+    @Test
+    public void testUnregisterCoexCallback() throws Exception {
+        mWifiManager.unregisterCoexCallback(mCoexCallback);
+        verify(mWifiService).unregisterCoexCallback(any());
+    }
+
+    /**
+     * Verify client unregisterCoexCallback with null callback will cause an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testUnregisterCoexCallbackWithNullCallback() throws Exception {
+        mWifiManager.unregisterCoexCallback(null);
+    }
+
+
+    /**
      * Check the call to startSoftAp calls WifiService to startSoftAp with the provided
      * WifiConfiguration.  Verify that the return value is propagated to the caller.
      */