Merge "Expand UidChecker to check new class initializations."
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 029699e..ca921ff 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -150,12 +150,10 @@
         ":current-support-api",
         ":current-androidx-api",
     ],
-    create_stubs: false,
 }
 
 doc_defaults {
     name: "framework-dokka-docs-default",
-    create_stubs: false,
 }
 
 droiddoc {
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 9ac8c87..4f6c21a 100644
--- a/apct-tests/perftests/autofill/Android.bp
+++ b/apct-tests/perftests/autofill/Android.bp
@@ -20,8 +20,9 @@
         "androidx.test.rules",
         "androidx.annotation_annotation",
         "apct-perftests-utils",
-        "collector-device-lib-platform",
+        "collector-device-lib",
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
+    data: [":perfetto_artifacts"],
 }
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index 51f6a76..57595a2 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -16,11 +16,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.perftests.autofill">
 
-    <uses-sdk android:targetSdkVersion="28" />
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
-
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name="android.perftests.utils.PerfTestActivity"
diff --git a/apct-tests/perftests/autofill/AndroidTest.xml b/apct-tests/perftests/autofill/AndroidTest.xml
index 29f9f94..eee7bdc 100644
--- a/apct-tests/perftests/autofill/AndroidTest.xml
+++ b/apct-tests/perftests/autofill/AndroidTest.xml
@@ -21,8 +21,40 @@
         <option name="test-file-name" value="AutofillPerfTests.apk" />
     </target_preparer>
 
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.autofill" />
         <option name="hidden-api-checks" value="false"/>
+
+        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
     </test>
 </configuration>
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 04432f2..fc45d4a 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -22,5 +22,6 @@
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
+    data: [":perfetto_artifacts"],
     certificate: "platform",
 }
diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml
index e4196dd..cb05651 100644
--- a/apct-tests/perftests/multiuser/AndroidManifest.xml
+++ b/apct-tests/perftests/multiuser/AndroidManifest.xml
@@ -17,7 +17,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.perftests.multiuser">
 
-    <uses-sdk android:targetSdkVersion="28" />
 
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
@@ -25,8 +24,6 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index 9117561..c7929af 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -16,14 +16,48 @@
 <configuration description="Runs MultiUserPerfTests metric instrumentation.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-metric-instrumentation" />
+
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="MultiUserPerfTests.apk" />
         <option name="test-file-name" value="MultiUserPerfDummyApp.apk" />
     </target_preparer>
 
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.multiuser" />
         <option name="hidden-api-checks" value="false"/>
+
+        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
     </test>
 </configuration>
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp
index 49952dc..9f795a7 100644
--- a/apct-tests/perftests/textclassifier/Android.bp
+++ b/apct-tests/perftests/textclassifier/Android.bp
@@ -19,7 +19,9 @@
         "androidx.test.rules",
         "androidx.annotation_annotation",
         "apct-perftests-utils",
+        "collector-device-lib-platform",
     ],
+    data: [":perfetto_artifacts"],
     platform_apis: true,
     test_suites: ["device-tests"],
 }
diff --git a/apct-tests/perftests/textclassifier/AndroidTest.xml b/apct-tests/perftests/textclassifier/AndroidTest.xml
index 3df51b8..3fac462 100644
--- a/apct-tests/perftests/textclassifier/AndroidTest.xml
+++ b/apct-tests/perftests/textclassifier/AndroidTest.xml
@@ -21,8 +21,40 @@
         <option name="test-file-name" value="TextClassifierPerfTests.apk" />
     </target_preparer>
 
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.textclassifier" />
         <option name="hidden-api-checks" value="false"/>
+
+         <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
     </test>
 </configuration>
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
index 14a121d..324def8 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
+import android.service.textclassifier.TextClassifierService;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
@@ -25,48 +26,73 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
 
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.Random;
 
-@RunWith(Parameterized.class)
 @LargeTest
 public class TextClassifierPerfTest {
-    /** Request contains meaning text, rather than garbled text. */
-    private static final int ACTUAL_REQUEST = 0;
-    private static final String RANDOM_CHAR_SET = "abcdefghijklmnopqrstuvwxyz0123456789";
+    private static final String TEXT = " Oh hi Mark, the number is (323) 654-6192.\n"
+            + "Anyway, I'll meet you at 1600 Pennsylvania Avenue NW.\n"
+            + "My flight is LX 38 and I'll arrive at 8:00pm.\n"
+            + "Also, check out www.google.com.\n";
 
     @Rule
     public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
-    @Parameterized.Parameters(name = "size{0}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][]{{ACTUAL_REQUEST}, {10}, {100}, {1000}});
-    }
-
     private TextClassifier mTextClassifier;
-    private final int mSize;
-
-    public TextClassifierPerfTest(int size) {
-        mSize = size;
-    }
 
     @Before
     public void setUp() {
         Context context = InstrumentationRegistry.getTargetContext();
-        TextClassificationManager textClassificationManager =
-                context.getSystemService(TextClassificationManager.class);
-        mTextClassifier = textClassificationManager.getTextClassifier(TextClassifier.LOCAL);
+        mTextClassifier = TextClassifierService.getDefaultTextClassifierImplementation(context);
+    }
+
+    @Test
+    public void testClassifyText() {
+        TextClassification.Request request =
+                new TextClassification.Request.Builder(TEXT, 0, TEXT.length()).build();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mTextClassifier.classifyText(request);
+        }
+    }
+
+    @Test
+    public void testSuggestSelection() {
+        // Trying to select the phone number.
+        TextSelection.Request request =
+                new TextSelection.Request.Builder(
+                        TEXT,
+                        /* startIndex= */ 28,
+                        /* endIndex= */29)
+                        .build();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mTextClassifier.suggestSelection(request);
+        }
+    }
+
+    @Test
+    public void testGenerateLinks() {
+        TextLinks.Request request =
+                new TextLinks.Request.Builder(TEXT).build();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mTextClassifier.generateLinks(request);
+        }
     }
 
     @Test
     public void testSuggestConversationActions() {
-        String text = mSize == ACTUAL_REQUEST ? "Where are you?" : generateRandomString(mSize);
-        ConversationActions.Request request = createConversationActionsRequest(text);
+        ConversationActions.Message message =
+                new ConversationActions.Message.Builder(
+                        ConversationActions.Message.PERSON_USER_OTHERS)
+                        .setText(TEXT)
+                        .build();
+        ConversationActions.Request request = new ConversationActions.Request.Builder(
+                Collections.singletonList(message))
+                .build();
+
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mTextClassifier.suggestConversationActions(request);
@@ -75,36 +101,10 @@
 
     @Test
     public void testDetectLanguage() {
-        String text = mSize == ACTUAL_REQUEST
-                ? "これは日本語のテキストです" : generateRandomString(mSize);
-        TextLanguage.Request request = createTextLanguageRequest(text);
+        TextLanguage.Request request = new TextLanguage.Request.Builder(TEXT).build();
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mTextClassifier.detectLanguage(request);
         }
     }
-
-    private static ConversationActions.Request createConversationActionsRequest(CharSequence text) {
-        ConversationActions.Message message =
-                new ConversationActions.Message.Builder(
-                        ConversationActions.Message.PERSON_USER_OTHERS)
-                        .setText(text)
-                        .build();
-        return new ConversationActions.Request.Builder(Collections.singletonList(message))
-                .build();
-    }
-
-    private static TextLanguage.Request createTextLanguageRequest(CharSequence text) {
-        return new TextLanguage.Request.Builder(text).build();
-    }
-
-    private static String generateRandomString(int length) {
-        Random random = new Random();
-        StringBuilder stringBuilder = new StringBuilder(length);
-        for (int i = 0; i < length; i++) {
-            int index = random.nextInt(RANDOM_CHAR_SET.length());
-            stringBuilder.append(RANDOM_CHAR_SET.charAt(index));
-        }
-        return stringBuilder.toString();
-    }
 }
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 12ec9eb4..7851087 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -803,8 +803,8 @@
      * <b>only</b> be used for situations where it is actually required that the alarm go off while
      * in idle -- a reasonable example would be for a calendar notification that should make a
      * sound so the user is aware of it.  When the alarm is dispatched, the app will also be
-     * added to the system's temporary whitelist for approximately 10 seconds to allow that
-     * application to acquire further wake locks in which to complete its work.</p>
+     * added to the system's temporary power exemption list for approximately 10 seconds to allow
+     * that application to acquire further wake locks in which to complete its work.</p>
      *
      * <p>These alarms can significantly impact the power use
      * of the device when idle (and thus cause significant battery blame to the app scheduling
@@ -855,8 +855,8 @@
      * be used for situations where it is actually required that the alarm go off while in
      * idle -- a reasonable example would be for a calendar notification that should make a
      * sound so the user is aware of it.  When the alarm is dispatched, the app will also be
-     * added to the system's temporary whitelist for approximately 10 seconds to allow that
-     * application to acquire further wake locks in which to complete its work.</p>
+     * added to the system's temporary power exemption list for approximately 10 seconds to allow
+     * that application to acquire further wake locks in which to complete its work.</p>
      *
      * <p>These alarms can significantly impact the power use
      * of the device when idle (and thus cause significant battery blame to the app scheduling
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index 6d23635..876d73a 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -67,8 +67,8 @@
  * Class to keep track of the information related to "force app standby", which includes:
  * - OP_RUN_ANY_IN_BACKGROUND for each package
  * - UID foreground/active state
- * - User+system power save whitelist
- * - Temporary power save whitelist
+ * - User+system power save exemption list
+ * - Temporary power save exemption list
  * - Global "force all apps standby" mode enforced by battery saver.
  *
  * Test: atest com.android.server.AppStateTrackerTest
@@ -110,25 +110,25 @@
     final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
 
     /**
-     * System except-idle + user whitelist in the device idle controller.
+     * System except-idle + user exemption list in the device idle controller.
      */
     @GuardedBy("mLock")
-    private int[] mPowerWhitelistedAllAppIds = new int[0];
+    private int[] mPowerExemptAllAppIds = new int[0];
 
     /**
-     * User whitelisted apps in the device idle controller.
+     * User exempted apps in the device idle controller.
      */
     @GuardedBy("mLock")
-    private int[] mPowerWhitelistedUserAppIds = new int[0];
+    private int[] mPowerExemptUserAppIds = new int[0];
 
     @GuardedBy("mLock")
-    private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
+    private int[] mTempExemptAppIds = mPowerExemptAllAppIds;
 
     /**
      * Per-user packages that are in the EXEMPT bucket.
      */
     @GuardedBy("mLock")
-    private final SparseSetArray<String> mExemptedPackages = new SparseSetArray<>();
+    private final SparseSetArray<String> mExemptBucketPackages = new SparseSetArray<>();
 
     @GuardedBy("mLock")
     final ArraySet<Listener> mListeners = new ArraySet<>();
@@ -177,10 +177,10 @@
         int UID_FG_STATE_CHANGED = 0;
         int UID_ACTIVE_STATE_CHANGED = 1;
         int RUN_ANY_CHANGED = 2;
-        int ALL_UNWHITELISTED = 3;
-        int ALL_WHITELIST_CHANGED = 4;
-        int TEMP_WHITELIST_CHANGED = 5;
-        int EXEMPT_CHANGED = 6;
+        int ALL_UNEXEMPTED = 3;
+        int ALL_EXEMPTION_LIST_CHANGED = 4;
+        int TEMP_EXEMPTION_LIST_CHANGED = 5;
+        int EXEMPT_BUCKET_CHANGED = 6;
         int FORCE_ALL_CHANGED = 7;
         int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
 
@@ -192,10 +192,10 @@
             "UID_FG_STATE_CHANGED",
             "UID_ACTIVE_STATE_CHANGED",
             "RUN_ANY_CHANGED",
-            "ALL_UNWHITELISTED",
-            "ALL_WHITELIST_CHANGED",
-            "TEMP_WHITELIST_CHANGED",
-            "EXEMPT_CHANGED",
+            "ALL_UNEXEMPTED",
+            "ALL_EXEMPTION_LIST_CHANGED",
+            "TEMP_EXEMPTION_LIST_CHANGED",
+            "EXEMPT_BUCKET_CHANGED",
             "FORCE_ALL_CHANGED",
             "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED",
 
@@ -308,38 +308,39 @@
         }
 
         /**
-         * This is called when an app-id(s) is removed from the power save whitelist.
+         * This is called when an app-id(s) is removed from the power save allow-list.
          */
-        private void onPowerSaveUnwhitelisted(AppStateTrackerImpl sender) {
+        private void onPowerSaveUnexempted(AppStateTrackerImpl sender) {
             updateAllJobs();
             unblockAllUnrestrictedAlarms();
         }
 
         /**
-         * This is called when the power save whitelist changes, excluding the
-         * {@link #onPowerSaveUnwhitelisted} case.
+         * This is called when the power save exemption list changes, excluding the
+         * {@link #onPowerSaveUnexempted} case.
          */
-        private void onPowerSaveWhitelistedChanged(AppStateTrackerImpl sender) {
+        private void onPowerSaveExemptionListChanged(AppStateTrackerImpl sender) {
             updateAllJobs();
         }
 
         /**
-         * This is called when the temp whitelist changes.
+         * This is called when the temp exemption list changes.
          */
-        private void onTempPowerSaveWhitelistChanged(AppStateTrackerImpl sender) {
+        private void onTempPowerSaveExemptionListChanged(AppStateTrackerImpl sender) {
 
             // TODO This case happens rather frequently; consider optimizing and update jobs
             // only for affected app-ids.
 
             updateAllJobs();
 
-            // Note when an app is just put in the temp whitelist, we do *not* drain pending alarms.
+            // Note when an app is just put in the temp exemption list, we do *not* drain pending
+            // alarms.
         }
 
         /**
          * This is called when the EXEMPT bucket is updated.
          */
-        private void onExemptChanged(AppStateTrackerImpl sender) {
+        private void onExemptBucketChanged(AppStateTrackerImpl sender) {
             // This doesn't happen very often, so just re-evaluate all jobs / alarms.
             updateAllJobs();
             unblockAllUnrestrictedAlarms();
@@ -709,8 +710,8 @@
                     && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 final String pkgName = intent.getData().getSchemeSpecificPart();
-                if (mExemptedPackages.remove(userId, pkgName)) {
-                    mHandler.notifyExemptChanged();
+                if (mExemptBucketPackages.remove(userId, pkgName)) {
+                    mHandler.notifyExemptBucketChanged();
                 }
             }
         }
@@ -727,12 +728,12 @@
             synchronized (mLock) {
                 final boolean changed;
                 if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
-                    changed = mExemptedPackages.add(userId, packageName);
+                    changed = mExemptBucketPackages.add(userId, packageName);
                 } else {
-                    changed = mExemptedPackages.remove(userId, packageName);
+                    changed = mExemptBucketPackages.remove(userId, packageName);
                 }
                 if (changed) {
-                    mHandler.notifyExemptChanged();
+                    mHandler.notifyExemptBucketChanged();
                 }
             }
         }
@@ -748,13 +749,13 @@
         private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
         private static final int MSG_UID_FG_STATE_CHANGED = 1;
         private static final int MSG_RUN_ANY_CHANGED = 3;
-        private static final int MSG_ALL_UNWHITELISTED = 4;
-        private static final int MSG_ALL_WHITELIST_CHANGED = 5;
-        private static final int MSG_TEMP_WHITELIST_CHANGED = 6;
+        private static final int MSG_ALL_UNEXEMPTED = 4;
+        private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5;
+        private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6;
         private static final int MSG_FORCE_ALL_CHANGED = 7;
         private static final int MSG_USER_REMOVED = 8;
         private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
-        private static final int MSG_EXEMPT_CHANGED = 10;
+        private static final int MSG_EXEMPT_BUCKET_CHANGED = 10;
 
         private static final int MSG_ON_UID_STATE_CHANGED = 11;
         private static final int MSG_ON_UID_ACTIVE = 12;
@@ -777,19 +778,19 @@
             obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
         }
 
-        public void notifyAllUnwhitelisted() {
-            removeMessages(MSG_ALL_UNWHITELISTED);
-            obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
+        public void notifyAllUnexempted() {
+            removeMessages(MSG_ALL_UNEXEMPTED);
+            obtainMessage(MSG_ALL_UNEXEMPTED).sendToTarget();
         }
 
-        public void notifyAllWhitelistChanged() {
-            removeMessages(MSG_ALL_WHITELIST_CHANGED);
-            obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
+        public void notifyAllExemptionListChanged() {
+            removeMessages(MSG_ALL_EXEMPTION_LIST_CHANGED);
+            obtainMessage(MSG_ALL_EXEMPTION_LIST_CHANGED).sendToTarget();
         }
 
-        public void notifyTempWhitelistChanged() {
-            removeMessages(MSG_TEMP_WHITELIST_CHANGED);
-            obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
+        public void notifyTempExemptionListChanged() {
+            removeMessages(MSG_TEMP_EXEMPTION_LIST_CHANGED);
+            obtainMessage(MSG_TEMP_EXEMPTION_LIST_CHANGED).sendToTarget();
         }
 
         public void notifyForceAllAppsStandbyChanged() {
@@ -802,9 +803,9 @@
             obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
         }
 
-        public void notifyExemptChanged() {
-            removeMessages(MSG_EXEMPT_CHANGED);
-            obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget();
+        public void notifyExemptBucketChanged() {
+            removeMessages(MSG_EXEMPT_BUCKET_CHANGED);
+            obtainMessage(MSG_EXEMPT_BUCKET_CHANGED).sendToTarget();
         }
 
         public void doUserRemoved(int userId) {
@@ -866,32 +867,32 @@
                     mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start);
                     return;
 
-                case MSG_ALL_UNWHITELISTED:
+                case MSG_ALL_UNEXEMPTED:
                     for (Listener l : cloneListeners()) {
-                        l.onPowerSaveUnwhitelisted(sender);
+                        l.onPowerSaveUnexempted(sender);
                     }
-                    mStatLogger.logDurationStat(Stats.ALL_UNWHITELISTED, start);
+                    mStatLogger.logDurationStat(Stats.ALL_UNEXEMPTED, start);
                     return;
 
-                case MSG_ALL_WHITELIST_CHANGED:
+                case MSG_ALL_EXEMPTION_LIST_CHANGED:
                     for (Listener l : cloneListeners()) {
-                        l.onPowerSaveWhitelistedChanged(sender);
+                        l.onPowerSaveExemptionListChanged(sender);
                     }
-                    mStatLogger.logDurationStat(Stats.ALL_WHITELIST_CHANGED, start);
+                    mStatLogger.logDurationStat(Stats.ALL_EXEMPTION_LIST_CHANGED, start);
                     return;
 
-                case MSG_TEMP_WHITELIST_CHANGED:
+                case MSG_TEMP_EXEMPTION_LIST_CHANGED:
                     for (Listener l : cloneListeners()) {
-                        l.onTempPowerSaveWhitelistChanged(sender);
+                        l.onTempPowerSaveExemptionListChanged(sender);
                     }
-                    mStatLogger.logDurationStat(Stats.TEMP_WHITELIST_CHANGED, start);
+                    mStatLogger.logDurationStat(Stats.TEMP_EXEMPTION_LIST_CHANGED, start);
                     return;
 
-                case MSG_EXEMPT_CHANGED:
+                case MSG_EXEMPT_BUCKET_CHANGED:
                     for (Listener l : cloneListeners()) {
-                        l.onExemptChanged(sender);
+                        l.onExemptBucketChanged(sender);
                     }
-                    mStatLogger.logDurationStat(Stats.EXEMPT_CHANGED, start);
+                    mStatLogger.logDurationStat(Stats.EXEMPT_BUCKET_CHANGED, start);
                     return;
 
                 case MSG_FORCE_ALL_CHANGED:
@@ -1004,7 +1005,7 @@
             }
             cleanUpArrayForUser(mActiveUids, removedUserId);
             cleanUpArrayForUser(mForegroundUids, removedUserId);
-            mExemptedPackages.remove(removedUserId);
+            mExemptBucketPackages.remove(removedUserId);
         }
     }
 
@@ -1020,39 +1021,39 @@
     }
 
     /**
-     * Called by device idle controller to update the power save whitelists.
+     * Called by device idle controller to update the power save exemption lists.
      */
-    public void setPowerSaveWhitelistAppIds(
-            int[] powerSaveWhitelistExceptIdleAppIdArray,
-            int[] powerSaveWhitelistUserAppIdArray,
-            int[] tempWhitelistAppIdArray) {
+    public void setPowerSaveExemptionListAppIds(
+            int[] powerSaveExemptionListExceptIdleAppIdArray,
+            int[] powerSaveExemptionListUserAppIdArray,
+            int[] tempExemptionListAppIdArray) {
         synchronized (mLock) {
-            final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
-            final int[] previousTempWhitelist = mTempWhitelistedAppIds;
+            final int[] previousExemptionList = mPowerExemptAllAppIds;
+            final int[] previousTempExemptionList = mTempExemptAppIds;
 
-            mPowerWhitelistedAllAppIds = powerSaveWhitelistExceptIdleAppIdArray;
-            mTempWhitelistedAppIds = tempWhitelistAppIdArray;
-            mPowerWhitelistedUserAppIds = powerSaveWhitelistUserAppIdArray;
+            mPowerExemptAllAppIds = powerSaveExemptionListExceptIdleAppIdArray;
+            mTempExemptAppIds = tempExemptionListAppIdArray;
+            mPowerExemptUserAppIds = powerSaveExemptionListUserAppIdArray;
 
-            if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
-                mHandler.notifyAllUnwhitelisted();
-            } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
-                mHandler.notifyAllWhitelistChanged();
+            if (isAnyAppIdUnexempt(previousExemptionList, mPowerExemptAllAppIds)) {
+                mHandler.notifyAllUnexempted();
+            } else if (!Arrays.equals(previousExemptionList, mPowerExemptAllAppIds)) {
+                mHandler.notifyAllExemptionListChanged();
             }
 
-            if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
-                mHandler.notifyTempWhitelistChanged();
+            if (!Arrays.equals(previousTempExemptionList, mTempExemptAppIds)) {
+                mHandler.notifyTempExemptionListChanged();
             }
 
         }
     }
 
     /**
-     * @retunr true if a sorted app-id array {@code prevArray} has at least one element
+     * @return true if a sorted app-id array {@code prevArray} has at least one element
      * that's not in a sorted app-id array {@code newArray}.
      */
     @VisibleForTesting
-    static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
+    static boolean isAnyAppIdUnexempt(int[] prevArray, int[] newArray) {
         int i1 = 0;
         int i2 = 0;
         boolean prevFinished;
@@ -1100,7 +1101,7 @@
      */
     public boolean areAlarmsRestricted(int uid, @NonNull String packageName,
             boolean isExemptOnBatterySaver) {
-        return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false,
+        return isRestricted(uid, packageName, /*useTempExemptionListToo=*/ false,
                 isExemptOnBatterySaver);
     }
 
@@ -1109,7 +1110,7 @@
      */
     public boolean areJobsRestricted(int uid, @NonNull String packageName,
             boolean hasForegroundExemption) {
-        return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true,
+        return isRestricted(uid, packageName, /*useTempExemptionListToo=*/ true,
                 hasForegroundExemption);
     }
 
@@ -1127,17 +1128,16 @@
      * @return whether force-app-standby is effective for a UID package-name.
      */
     private boolean isRestricted(int uid, @NonNull String packageName,
-            boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
+            boolean useTempExemptionListToo, boolean exemptOnBatterySaver) {
         if (isUidActive(uid)) {
             return false;
         }
         synchronized (mLock) {
-            // Whitelisted?
             final int appId = UserHandle.getAppId(uid);
-            if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
+            if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
                 return false;
             }
-            if (useTempWhitelistToo && ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
+            if (useTempExemptionListToo && ArrayUtils.contains(mTempExemptAppIds, appId)) {
                 return false;
             }
             if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) {
@@ -1148,7 +1148,7 @@
             }
             final int userId = UserHandle.getUserId(uid);
             if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
-                    && mExemptedPackages.contains(userId, packageName)) {
+                    && mExemptBucketPackages.contains(userId, packageName)) {
                 return false;
             }
             return mForceAllAppsStandby;
@@ -1225,34 +1225,34 @@
     }
 
     /**
-     * @return whether a UID is in the user / system defined power-save whitelist or not.
+     * @return whether a UID is in the user / system defined power-save exemption list or not.
      *
      * Note clients normally shouldn't need to access it. It's only for dumpsys.
      */
-    public boolean isUidPowerSaveWhitelisted(int uid) {
+    public boolean isUidPowerSaveExempt(int uid) {
         synchronized (mLock) {
-            return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
+            return ArrayUtils.contains(mPowerExemptAllAppIds, UserHandle.getAppId(uid));
         }
     }
 
     /**
      * @param uid the uid to check for
-     * @return whether a UID is in the user defined power-save whitelist or not.
+     * @return whether a UID is in the user defined power-save exemption list or not.
      */
-    public boolean isUidPowerSaveUserWhitelisted(int uid) {
+    public boolean isUidPowerSaveUserExempt(int uid) {
         synchronized (mLock) {
-            return ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
+            return ArrayUtils.contains(mPowerExemptUserAppIds, UserHandle.getAppId(uid));
         }
     }
 
     /**
-     * @return whether a UID is in the temp power-save whitelist or not.
+     * @return whether a UID is in the temp power-save exemption list or not.
      *
      * Note clients normally shouldn't need to access it. It's only for dumpsys.
      */
-    public boolean isUidTempPowerSaveWhitelisted(int uid) {
+    public boolean isUidTempPowerSaveExempt(int uid) {
         synchronized (mLock) {
-            return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
+            return ArrayUtils.contains(mTempExemptAppIds, UserHandle.getAppId(uid));
         }
     }
 
@@ -1290,25 +1290,25 @@
             pw.print("Foreground uids: ");
             dumpUids(pw, mForegroundUids);
 
-            pw.print("Except-idle + user whitelist appids: ");
-            pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
+            pw.print("Except-idle + user exemption list appids: ");
+            pw.println(Arrays.toString(mPowerExemptAllAppIds));
 
-            pw.print("User whitelist appids: ");
-            pw.println(Arrays.toString(mPowerWhitelistedUserAppIds));
+            pw.print("User exemption list appids: ");
+            pw.println(Arrays.toString(mPowerExemptUserAppIds));
 
-            pw.print("Temp whitelist appids: ");
-            pw.println(Arrays.toString(mTempWhitelistedAppIds));
+            pw.print("Temp exemption list appids: ");
+            pw.println(Arrays.toString(mTempExemptAppIds));
 
-            pw.println("Exempted packages:");
+            pw.println("Exempted bucket packages:");
             pw.increaseIndent();
-            for (int i = 0; i < mExemptedPackages.size(); i++) {
+            for (int i = 0; i < mExemptBucketPackages.size(); i++) {
                 pw.print("User ");
-                pw.print(mExemptedPackages.keyAt(i));
+                pw.print(mExemptBucketPackages.keyAt(i));
                 pw.println();
 
                 pw.increaseIndent();
-                for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
-                    pw.print(mExemptedPackages.valueAt(i, j));
+                for (int j = 0; j < mExemptBucketPackages.sizeAt(i); j++) {
+                    pw.print(mExemptBucketPackages.valueAt(i, j));
                     pw.println();
                 }
                 pw.decreaseIndent();
@@ -1372,24 +1372,24 @@
                 }
             }
 
-            for (int appId : mPowerWhitelistedAllAppIds) {
-                proto.write(AppStateTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
+            for (int appId : mPowerExemptAllAppIds) {
+                proto.write(AppStateTrackerProto.POWER_SAVE_EXEMPT_APP_IDS, appId);
             }
 
-            for (int appId : mPowerWhitelistedUserAppIds) {
-                proto.write(AppStateTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
+            for (int appId : mPowerExemptUserAppIds) {
+                proto.write(AppStateTrackerProto.POWER_SAVE_USER_EXEMPT_APP_IDS, appId);
             }
 
-            for (int appId : mTempWhitelistedAppIds) {
-                proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
+            for (int appId : mTempExemptAppIds) {
+                proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_EXEMPT_APP_IDS, appId);
             }
 
-            for (int i = 0; i < mExemptedPackages.size(); i++) {
-                for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
-                    final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_PACKAGES);
+            for (int i = 0; i < mExemptBucketPackages.size(); i++) {
+                for (int j = 0; j < mExemptBucketPackages.sizeAt(i); j++) {
+                    final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_BUCKET_PACKAGES);
 
-                    proto.write(ExemptedPackage.USER_ID, mExemptedPackages.keyAt(i));
-                    proto.write(ExemptedPackage.PACKAGE_NAME, mExemptedPackages.valueAt(i, j));
+                    proto.write(ExemptedPackage.USER_ID, mExemptBucketPackages.keyAt(i));
+                    proto.write(ExemptedPackage.PACKAGE_NAME, mExemptBucketPackages.valueAt(i, j));
 
                     proto.end(token2);
                 }
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index b1bafee..6c3398f 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -3715,7 +3715,7 @@
     }
 
     private void passWhiteListsToForceAppStandbyTrackerLocked() {
-        mAppStateTracker.setPowerSaveWhitelistAppIds(
+        mAppStateTracker.setPowerSaveExemptionListAppIds(
                 mPowerSaveWhitelistExceptIdleAppIdArray,
                 mPowerSaveWhitelistUserAppIdArray,
                 mTempWhitelistAppIdArray);
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 6529503..4194fd0 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -2089,7 +2089,7 @@
             } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
                     || UserHandle.isSameApp(callingUid, mSystemUiUid)
                     || ((mAppStateTracker != null)
-                        && mAppStateTracker.isUidPowerSaveUserWhitelisted(callingUid)))) {
+                        && mAppStateTracker.isUidPowerSaveUserExempt(callingUid)))) {
                 flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
                 flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
             }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 4db4adc..3234b27 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -89,6 +89,7 @@
 import com.android.server.AppStateTrackerImpl;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
 import com.android.server.job.controllers.BackgroundJobsController;
@@ -975,24 +976,24 @@
     }
 
     @Override
-    public void onStartUser(int userHandle) {
+    public void onUserStarting(@NonNull TargetUser user) {
         synchronized (mLock) {
-            mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
+            mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier());
         }
         // Let's kick any outstanding jobs for this user.
         mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
     }
 
     @Override
-    public void onUnlockUser(int userHandle) {
+    public void onUserUnlocking(@NonNull TargetUser user) {
         // Let's kick any outstanding jobs for this user.
         mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
     }
 
     @Override
-    public void onStopUser(int userHandle) {
+    public void onUserStopping(@NonNull TargetUser user) {
         synchronized (mLock) {
-            mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userHandle);
+            mStartedUsers = ArrayUtils.removeInt(mStartedUsers, user.getUserIdentifier());
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index b632435..44c8fcf 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -91,9 +91,9 @@
             pw.print(" from ");
             UserHandle.formatUid(pw, uid);
             pw.print(mAppStateTracker.isUidActive(uid) ? " active" : " idle");
-            if (mAppStateTracker.isUidPowerSaveWhitelisted(uid) ||
-                    mAppStateTracker.isUidTempPowerSaveWhitelisted(uid)) {
-                pw.print(", whitelisted");
+            if (mAppStateTracker.isUidPowerSaveExempt(uid)
+                    || mAppStateTracker.isUidTempPowerSaveExempt(uid)) {
+                pw.print(", exempted");
             }
             pw.print(": ");
             pw.print(sourcePkg);
@@ -132,8 +132,8 @@
 
             proto.write(TrackedJob.IS_IN_FOREGROUND, mAppStateTracker.isUidActive(sourceUid));
             proto.write(TrackedJob.IS_WHITELISTED,
-                    mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
-                    mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
+                    mAppStateTracker.isUidPowerSaveExempt(sourceUid)
+                            || mAppStateTracker.isUidTempPowerSaveExempt(sourceUid));
 
             proto.write(TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
                     mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(sourceUid, sourcePkg));
diff --git a/api/current.txt b/api/current.txt
index a59c7b8..b70103b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11900,6 +11900,7 @@
     field public static final int INVALID_ID = -1; // 0xffffffff
     field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
     field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
+    field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
     field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
     field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
   }
@@ -24207,6 +24208,7 @@
     method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
     method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
     method public int getAllowedCapturePolicy();
+    method public int getAudioHwSyncForSession(int);
     method public android.media.AudioDeviceInfo[] getDevices(int);
     method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
     method public int getMode();
@@ -47864,6 +47866,7 @@
     method @Nullable public android.net.LinkProperties getLinkProperties();
     method public int getNetworkType();
     method public int getState();
+    method public int getTransportType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR;
   }
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 696e029..3f3b8ea 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -31,6 +31,14 @@
 
 }
 
+package android.media {
+
+  public class AudioManager {
+    field public static final int FLAG_FROM_KEY = 4096; // 0x1000
+  }
+
+}
+
 package android.net {
 
   public final class TetheringConstants {
diff --git a/api/system-current.txt b/api/system-current.txt
index 11db781..56059dd 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4201,6 +4201,7 @@
     method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
     method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4219,6 +4220,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
     method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4229,6 +4231,11 @@
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
     field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
+    field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+    field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+    field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+    field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+    field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
     field public static final int SUCCESS = 0; // 0x0
   }
@@ -10838,6 +10845,7 @@
     method @Deprecated public int getDataConnectionApnTypeBitMask();
     method @Deprecated public int getDataConnectionFailCause();
     method @Deprecated public int getDataConnectionState();
+    method public int getId();
   }
 
   public final class PreciseDisconnectCause {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 36ff20f..9c79612 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -417,7 +417,7 @@
     // this guest property specifies multi-display IDs to show the boot animation
     // multiple ids can be set with comma (,) as separator, for example:
     // setprop persist.boot.animation.displays 19260422155234049,19261083906282754
-    Vector<uint64_t> physicalDisplayIds;
+    Vector<PhysicalDisplayId> physicalDisplayIds;
     char displayValue[PROPERTY_VALUE_MAX] = "";
     property_get(DISPLAYS_PROP_NAME, displayValue, "");
     bool isValid = displayValue[0] != '\0';
@@ -435,7 +435,7 @@
     }
     if (isValid) {
         std::istringstream stream(displayValue);
-        for (PhysicalDisplayId id; stream >> id; ) {
+        for (PhysicalDisplayId id; stream >> id.value; ) {
             physicalDisplayIds.add(id);
             if (stream.peek() == ',')
                 stream.ignore();
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
index 02b27a8..403d8c5 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
@@ -29,4 +29,5 @@
   const int ODM_PARTITION = 0x00000020;
   const int OEM_PARTITION = 0x00000040;
   const int ACTOR_SIGNATURE = 0x00000080;
+  const int CONFIG_SIGNATURE = 0x0000100;
 }
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 34589a1..fd8b4eb 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -61,10 +61,13 @@
                               const ResourceId& target_resource) {
   static constexpr const PolicyBitmask sDefaultPolicies =
       PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
-      PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE;
+      PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE |
+      PolicyFlags::CONFIG_SIGNATURE;
 
   // If the resource does not have an overlayable definition, allow the resource to be overlaid if
-  // the overlay is preinstalled or signed with the same signature as the target.
+  // the overlay is preinstalled, signed with the same signature as the target or signed with the
+  // same signature as reference package defined in SystemConfig under 'overlay-config-signature'
+  // tag.
   if (!target_package.DefinesOverlayable()) {
     return (sDefaultPolicies & fulfilled_policies) != 0
                ? Result<Unit>({})
diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
index f7987b0..cdce451 100644
--- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
+++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
@@ -38,16 +38,18 @@
 constexpr const char* kPolicyOem = "oem";
 constexpr const char* kPolicyProduct = "product";
 constexpr const char* kPolicyPublic = "public";
+constexpr const char* kPolicyConfigSignature = "config_signature";
 constexpr const char* kPolicySignature = "signature";
 constexpr const char* kPolicySystem = "system";
 constexpr const char* kPolicyVendor = "vendor";
 
-inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = {
+inline static const std::array<std::pair<StringPiece, PolicyFlags>, 9> kPolicyStringToFlag = {
     std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE},
     {kPolicyOdm, PolicyFlags::ODM_PARTITION},
     {kPolicyOem, PolicyFlags::OEM_PARTITION},
     {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION},
     {kPolicyPublic, PolicyFlags::PUBLIC},
+    {kPolicyConfigSignature, PolicyFlags::CONFIG_SIGNATURE},
     {kPolicySignature, PolicyFlags::SIGNATURE},
     {kPolicySystem, PolicyFlags::SYSTEM_PARTITION},
     {kPolicyVendor, PolicyFlags::VENDOR_PARTITION},
diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h
index 4f2ee1c..854b57f 100644
--- a/cmds/idmap2/tests/R.h
+++ b/cmds/idmap2/tests/R.h
@@ -43,16 +43,17 @@
     constexpr ResourceId not_overlayable = 0x7f020003;
     constexpr ResourceId other = 0x7f020004;
     constexpr ResourceId policy_actor = 0x7f020005;
-    constexpr ResourceId policy_odm = 0x7f020006;
-    constexpr ResourceId policy_oem = 0x7f020007;
-    constexpr ResourceId policy_product = 0x7f020008;
-    constexpr ResourceId policy_public = 0x7f020009;
-    constexpr ResourceId policy_signature = 0x7f02000a;
-    constexpr ResourceId policy_system = 0x7f02000b;
-    constexpr ResourceId policy_system_vendor = 0x7f02000c;
-    constexpr ResourceId str1 = 0x7f02000d;
-    constexpr ResourceId str3 = 0x7f02000f;
-    constexpr ResourceId str4 = 0x7f020010;
+    constexpr ResourceId policy_config_signature = 0x7f020006;
+    constexpr ResourceId policy_odm = 0x7f020007;
+    constexpr ResourceId policy_oem = 0x7f020008;
+    constexpr ResourceId policy_product = 0x7f020009;
+    constexpr ResourceId policy_public = 0x7f02000a;
+    constexpr ResourceId policy_signature = 0x7f02000b;
+    constexpr ResourceId policy_system = 0x7f02000c;
+    constexpr ResourceId policy_system_vendor = 0x7f02000d;
+    constexpr ResourceId str1 = 0x7f02000e;
+    constexpr ResourceId str3 = 0x7f020010;
+    constexpr ResourceId str4 = 0x7f020011;
 
     namespace literal {  // NOLINT(runtime/indentation_namespace)
       inline const std::string str1 = hexify(R::target::string::str1);
@@ -94,13 +95,14 @@
   constexpr ResourceId not_overlayable = 0x7f010000;
   constexpr ResourceId other = 0x7f010001;
   constexpr ResourceId policy_actor = 0x7f010002;
-  constexpr ResourceId policy_odm = 0x7f010003;
-  constexpr ResourceId policy_oem = 0x7f010004;
-  constexpr ResourceId policy_product = 0x7f010005;
-  constexpr ResourceId policy_public = 0x7f010006;
-  constexpr ResourceId policy_signature = 0x7f010007;
-  constexpr ResourceId policy_system = 0x7f010008;
-  constexpr ResourceId policy_system_vendor = 0x7f010009;
+  constexpr ResourceId policy_config_signature = 0x7f010003;
+  constexpr ResourceId policy_odm = 0x7f010004;
+  constexpr ResourceId policy_oem = 0x7f010005;
+  constexpr ResourceId policy_product = 0x7f010006;
+  constexpr ResourceId policy_public = 0x7f010007;
+  constexpr ResourceId policy_signature = 0x7f010008;
+  constexpr ResourceId policy_system = 0x7f010009;
+  constexpr ResourceId policy_system_vendor = 0x7f01000a;
 }  // namespace R::system_overlay_invalid::string
 // clang-format on
 
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index de039f4..3ec6ac2 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -237,7 +237,7 @@
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
-  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U);
+  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U);
   ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
                               R::system_overlay_invalid::string::not_overlayable,
                               false /* rewrite */));
@@ -256,6 +256,10 @@
   ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
                               R::system_overlay_invalid::string::policy_public,
                               false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
+                              Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_config_signature,
+                              false /* rewrite */));
   ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
                               R::system_overlay_invalid::string::policy_signature,
                               false /* rewrite */));
@@ -298,8 +302,9 @@
   ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
 }
 
-// Overlays that are pre-installed or are signed with the same signature as the target can overlay
-// packages that have not defined overlayable resources.
+// Overlays that are pre-installed or are signed with the same signature as the target  or are signed
+// with the same signature as the reference package can overlay packages that have not defined
+// overlayable resources.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
   auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
     auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
@@ -309,7 +314,7 @@
 
     ASSERT_TRUE(resources) << resources.GetErrorMessage();
     auto& res = *resources;
-    ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U);
+    ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U);
     ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
                                 R::system_overlay_invalid::string::not_overlayable,
                                 false /* rewrite */));
@@ -330,6 +335,10 @@
     ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
                                 R::system_overlay_invalid::string::policy_public,
                                 false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
+                                Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_config_signature,
+                                false /* rewrite */));
     ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
                                 R::system_overlay_invalid::string::policy_signature,
                                 false /* rewrite */));
@@ -342,6 +351,7 @@
   };
 
   CheckEntries(PolicyFlags::SIGNATURE);
+  CheckEntries(PolicyFlags::CONFIG_SIGNATURE);
   CheckEntries(PolicyFlags::PRODUCT_PARTITION);
   CheckEntries(PolicyFlags::SYSTEM_PARTITION);
   CheckEntries(PolicyFlags::VENDOR_PARTITION);
diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h
index 74ea18f..9641f6b5 100644
--- a/cmds/idmap2/tests/TestConstants.h
+++ b/cmds/idmap2/tests/TestConstants.h
@@ -19,11 +19,11 @@
 
 namespace android::idmap2::TestConstants {
 
-constexpr const auto TARGET_CRC = 0x41c60c8c;
-constexpr const auto TARGET_CRC_STRING = "41c60c8c";
+constexpr const auto TARGET_CRC =  0x7c2d4719;
+constexpr const auto TARGET_CRC_STRING = "7c2d4719";
 
-constexpr const auto OVERLAY_CRC = 0xc054fb26;
-constexpr const auto OVERLAY_CRC_STRING = "c054fb26";
+constexpr const auto OVERLAY_CRC = 0x5afff726;
+constexpr const auto OVERLAY_CRC_STRING = "5afff726";
 
 }  // namespace android::idmap2::TestConstants
 
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
index 7c25985..dab25b1 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
index c75f3e1..c8b95c2 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
index 93dcc82..0a8b737 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-shared.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
index 5b8a6e4..fd41182 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
index 698a1fd..b24765f 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk
index 1db303f..870575e 100644
--- a/cmds/idmap2/tests/data/overlay/overlay.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
index 51e19de..e0fd204 100644
--- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
+++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
index 7119d82..ebaf49c 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -26,6 +26,7 @@
     <string name="policy_odm">policy_odm</string>
     <string name="policy_oem">policy_oem</string>
     <string name="policy_actor">policy_actor</string>
+    <string name="policy_config_signature">policy_config_signature</string>
 
     <!-- Requests to overlay a resource that is not declared as overlayable. -->
     <string name="not_overlayable">not_overlayable</string>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
index bd99098..a63daf8 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
index a0fba43..90d2803 100644
--- a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index ad4cd48..57e6c43 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -45,6 +45,10 @@
         <item type="string" name="policy_actor" />
     </policy>
 
+    <policy type="config_signature">
+        <item type="string" name="policy_config_signature"/>
+    </policy>
+
     <!-- Resources publicly overlayable -->
     <policy type="public">
         <item type="string" name="policy_public" />
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 5230e25..00909a9 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -37,6 +37,7 @@
     <string name="policy_system">policy_system</string>
     <string name="policy_system_vendor">policy_system_vendor</string>
     <string name="policy_actor">policy_actor</string>
+    <string name="policy_config_signature">policy_config_signature</string>
 
     <string name="other">other</string>
 </resources>
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index 58504a7..cc3491d 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index c80e5eb..4a58c5e 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index c1d8399..dec4a56 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -51,12 +51,11 @@
             "usage: %s [-hp] [-d display-id] [FILENAME]\n"
             "   -h: this message\n"
             "   -p: save the file as a png.\n"
-            "   -d: specify the physical display ID to capture (default: %"
-                    ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ")\n"
+            "   -d: specify the physical display ID to capture (default: %s)\n"
             "       see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
             "If FILENAME ends with .png it will be saved as a png.\n"
             "If FILENAME is not given, the results will be printed to stdout.\n",
-            pname, displayId);
+            pname, to_string(displayId).c_str());
 }
 
 static int32_t flinger2bitmapFormat(PixelFormat f)
@@ -137,7 +136,7 @@
                 png = true;
                 break;
             case 'd':
-                displayId = atoll(optarg);
+                displayId = PhysicalDisplayId(atoll(optarg));
                 break;
             case '?':
             case 'h':
@@ -182,16 +181,17 @@
     ProcessState::self()->setThreadPoolMaxThreadCount(0);
     ProcessState::self()->startThreadPool();
 
-    ui::Dataspace outDataspace;
-    sp<GraphicBuffer> outBuffer;
-
-    status_t result = ScreenshotClient::capture(*displayId, &outDataspace, &outBuffer);
+    ScreenCaptureResults captureResults;
+    status_t result = ScreenshotClient::captureDisplay(displayId->value, captureResults);
     if (result != NO_ERROR) {
         close(fd);
         return 1;
     }
 
-    result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
+    ui::Dataspace dataspace = captureResults.capturedDataspace;
+    sp<GraphicBuffer> buffer = captureResults.buffer;
+
+    result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
 
     if (base == nullptr || result != NO_ERROR) {
         String8 reason;
@@ -207,13 +207,13 @@
 
     if (png) {
         AndroidBitmapInfo info;
-        info.format = flinger2bitmapFormat(outBuffer->getPixelFormat());
+        info.format = flinger2bitmapFormat(buffer->getPixelFormat());
         info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
-        info.width = outBuffer->getWidth();
-        info.height = outBuffer->getHeight();
-        info.stride = outBuffer->getStride() * bytesPerPixel(outBuffer->getPixelFormat());
+        info.width = buffer->getWidth();
+        info.height = buffer->getHeight();
+        info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
 
-        int result = AndroidBitmap_compress(&info, static_cast<int32_t>(outDataspace), base,
+        int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
                                             ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
                                             [](void* fdPtr, const void* data, size_t size) -> bool {
                                                 int bytesWritten = write(*static_cast<int*>(fdPtr),
@@ -229,11 +229,11 @@
             notifyMediaScanner(fn);
         }
     } else {
-        uint32_t w = outBuffer->getWidth();
-        uint32_t h = outBuffer->getHeight();
-        uint32_t s = outBuffer->getStride();
-        uint32_t f = outBuffer->getPixelFormat();
-        uint32_t c = dataSpaceToInt(outDataspace);
+        uint32_t w = buffer->getWidth();
+        uint32_t h = buffer->getHeight();
+        uint32_t s = buffer->getStride();
+        uint32_t f = buffer->getPixelFormat();
+        uint32_t c = dataSpaceToInt(dataspace);
 
         write(fd, &w, 4);
         write(fd, &h, 4);
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index b7f23a6..6327490 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -526,19 +526,34 @@
     OnConfigUpdatedLocked(timestampNs, key, config);
 }
 
-void StatsLogProcessor::OnConfigUpdatedLocked(
-        const int64_t timestampNs, const ConfigKey& key, const StatsdConfig& config) {
+void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const ConfigKey& key,
+                                              const StatsdConfig& config, bool modularUpdate) {
     VLOG("Updated configuration for key %s", key.ToString().c_str());
-    sp<MetricsManager> newMetricsManager =
-            new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap, mPullerManager,
-                               mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
-    if (newMetricsManager->isConfigValid()) {
-        newMetricsManager->init();
-        mUidMap->OnConfigUpdated(key);
-        newMetricsManager->refreshTtl(timestampNs);
-        mMetricsManagers[key] = newMetricsManager;
-        VLOG("StatsdConfig valid");
+    // Create new config if this is not a modular update or if this is a new config.
+    const auto& it = mMetricsManagers.find(key);
+    bool configValid = false;
+    if (!modularUpdate || it == mMetricsManagers.end()) {
+        sp<MetricsManager> newMetricsManager =
+                new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap, mPullerManager,
+                                   mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
+        configValid = newMetricsManager->isConfigValid();
+        if (configValid) {
+            newMetricsManager->init();
+            mUidMap->OnConfigUpdated(key);
+            newMetricsManager->refreshTtl(timestampNs);
+            mMetricsManagers[key] = newMetricsManager;
+            VLOG("StatsdConfig valid");
+        }
     } else {
+        // Preserve the existing MetricsManager, update necessary components and metadata in place.
+        configValid = it->second->updateConfig(timestampNs, config);
+        if (configValid) {
+            // TODO(b/162323476): refresh TTL, ensure init() is handled properly.
+            mUidMap->OnConfigUpdated(key);
+
+        }
+    }
+    if (!configValid) {
         // If there is any error in the config, don't use it.
         // Remove any existing config with the same key.
         ALOGE("StatsdConfig NOT valid");
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 2384ed8..383dbd9 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -187,8 +187,8 @@
 
     void resetIfConfigTtlExpiredLocked(const int64_t timestampNs);
 
-    void OnConfigUpdatedLocked(
-        const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config);
+    void OnConfigUpdatedLocked(const int64_t currentTimestampNs, const ConfigKey& key,
+                               const StatsdConfig& config, bool modularUpdate = false);
 
     void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
 
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 60de1a2..189d811 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -195,6 +195,10 @@
     VLOG("~MetricsManager()");
 }
 
+bool MetricsManager::updateConfig(const int64_t currentTimeNs, const StatsdConfig& config) {
+    return mConfigValid;
+}
+
 void MetricsManager::initLogSourceWhiteList() {
     std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
     mAllowedLogSources.clear();
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index ad30a88..042de29 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -46,6 +46,8 @@
 
     virtual ~MetricsManager();
 
+    bool updateConfig(const int64_t currentTimeNs, const StatsdConfig& config);
+
     // Return whether the configuration is valid.
     bool isConfigValid() const;
 
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 6c50a8c..1bc84c5 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -17,6 +17,8 @@
 #ifndef STATSD_PACKAGE_INFO_LISTENER_H
 #define STATSD_PACKAGE_INFO_LISTENER_H
 
+#include <utils/RefBase.h>
+
 #include <string>
 
 namespace android {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 22250ae..622321b 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include "config/ConfigKey.h"
-#include "config/ConfigListener.h"
 #include "packages/PackageInfoListener.h"
 #include "stats_util.h"
 
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 04b00cb..14b74da 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -54,7 +54,6 @@
     ],
     installable: false,
     custom_template: "droiddoc-templates-sdk",
-    create_stubs: false,
 }
 
 java_library_static {
@@ -66,6 +65,7 @@
         "android.test.runner",
         "junit",
     ],
+    java_version: "1.8",
 }
 
 java_library_static {
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index 71561c3..39248730 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -49,7 +49,7 @@
         }
         try {
             if (isSet) {
-                am.setActivityController(new DummyActivityController(), true);
+                am.setActivityController(new NoOpActivityController(), true);
             } else {
                 am.setActivityController(null, true);
             }
@@ -80,9 +80,9 @@
     }
 
     /**
-     * Dummy, no interference, activity controller.
+     * No-op, no interference, activity controller.
      */
-    private class DummyActivityController extends IActivityController.Stub {
+    private class NoOpActivityController extends IActivityController.Stub {
         @Override
         public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
             /* do nothing and let activity proceed normally */
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
index d862e1c..e6fb7aa 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
@@ -45,7 +45,7 @@
 public class UiAutomatorTestCase extends TestCase {
 
     private static final String DISABLE_IME = "disable_ime";
-    private static final String DUMMY_IME_PACKAGE = "com.android.testing.dummyime";
+    private static final String STUB_IME_PACKAGE = "com.android.testing.stubime";
     private static final int NOT_A_SUBTYPE_ID = -1;
 
     private UiDevice mUiDevice;
@@ -58,7 +58,7 @@
         super.setUp();
         mShouldDisableIme = "true".equals(mParams.getString(DISABLE_IME));
         if (mShouldDisableIme) {
-            setDummyIme();
+            setStubIme();
         }
     }
 
@@ -128,7 +128,7 @@
         SystemClock.sleep(ms);
     }
 
-    private void setDummyIme() {
+    private void setStubIme() {
         Context context = ActivityThread.currentApplication();
         if (context == null) {
             throw new RuntimeException("ActivityThread.currentApplication() is null.");
@@ -138,13 +138,13 @@
         List<InputMethodInfo> infos = im.getInputMethodList();
         String id = null;
         for (InputMethodInfo info : infos) {
-            if (DUMMY_IME_PACKAGE.equals(info.getComponent().getPackageName())) {
+            if (STUB_IME_PACKAGE.equals(info.getComponent().getPackageName())) {
                 id = info.getId();
             }
         }
         if (id == null) {
             throw new RuntimeException(String.format(
-                    "Required testing fixture missing: IME package (%s)", DUMMY_IME_PACKAGE));
+                    "Required testing fixture missing: IME package (%s)", STUB_IME_PACKAGE));
         }
         if (context.checkSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
                 != PackageManager.PERMISSION_GRANTED) {
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 35cf39f..bc8db02 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -183,7 +183,7 @@
 
     // This is to work around a bug in b/34736819. This needs to be removed once app team
     // fixes their side.
-    private AnimatorListenerAdapter mDummyListener = new AnimatorListenerAdapter() {
+    private AnimatorListenerAdapter mAnimationEndListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
             if (mNodeMap.get(animation) == null) {
@@ -1186,7 +1186,7 @@
     }
 
     private void startAnimation() {
-        addDummyListener();
+        addAnimationEndListener();
 
         // Register animation callback
         addAnimationCallback(0);
@@ -1243,15 +1243,15 @@
 
     // This is to work around the issue in b/34736819, as the old behavior in AnimatorSet had
     // masked a real bug in play movies. TODO: remove this and below once the root cause is fixed.
-    private void addDummyListener() {
+    private void addAnimationEndListener() {
         for (int i = 1; i < mNodes.size(); i++) {
-            mNodes.get(i).mAnimation.addListener(mDummyListener);
+            mNodes.get(i).mAnimation.addListener(mAnimationEndListener);
         }
     }
 
-    private void removeDummyListener() {
+    private void removeAnimationEndListener() {
         for (int i = 1; i < mNodes.size(); i++) {
-            mNodes.get(i).mAnimation.removeListener(mDummyListener);
+            mNodes.get(i).mAnimation.removeListener(mAnimationEndListener);
         }
     }
 
@@ -1301,7 +1301,7 @@
                 tmpListeners.get(i).onAnimationEnd(this, mReversing);
             }
         }
-        removeDummyListener();
+        removeAnimationEndListener();
         mSelfPulse = true;
         mReversing = false;
     }
@@ -1346,7 +1346,7 @@
         anim.mNodeMap = new ArrayMap<Animator, Node>();
         anim.mNodes = new ArrayList<Node>(nodeCount);
         anim.mEvents = new ArrayList<AnimationEvent>();
-        anim.mDummyListener = new AnimatorListenerAdapter() {
+        anim.mAnimationEndListener = new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (anim.mNodeMap.get(animation) == null) {
@@ -1369,7 +1369,7 @@
             final Node node = mNodes.get(n);
             Node nodeClone = node.clone();
             // Remove the old internal listener from the cloned child
-            nodeClone.mAnimation.removeListener(mDummyListener);
+            nodeClone.mAnimation.removeListener(mAnimationEndListener);
             clonesMap.put(node, nodeClone);
             anim.mNodes.add(nodeClone);
             anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
@@ -2087,7 +2087,7 @@
          * animation starts.
          */
         public Builder after(long delay) {
-            // setup dummy ValueAnimator just to run the clock
+            // setup a ValueAnimator just to run the clock
             ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
             anim.setDuration(delay);
             after(anim);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4a982dd..522b8cc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -35,6 +35,7 @@
 import android.annotation.StyleRes;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.annotation.UiContext;
 import android.app.VoiceInteractor.Request;
 import android.app.admin.DevicePolicyManager;
 import android.app.assist.AssistContent;
@@ -726,6 +727,7 @@
  * upload, independent of whether the original activity is paused, stopped,
  * or finished.
  */
+@UiContext
 public class Activity extends ContextThemeWrapper
         implements LayoutInflater.Factory2,
         Window.Callback, KeyEvent.Callback,
@@ -2878,7 +2880,7 @@
      * Return the number of actions that will be displayed in the picture-in-picture UI when the
      * user interacts with the activity currently in picture-in-picture mode. This number may change
      * if the global configuration changes (ie. if the device is plugged into an external display),
-     * but will always be larger than three.
+     * but will always be at least three.
      */
     public int getMaxNumPictureInPictureActions() {
         try {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f474389..1f8cf8a 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -52,23 +52,14 @@
      * if in the same profile group.
      * Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
      */
-    public static final int ALLOW_NON_FULL_IN_PROFILE_OR_FULL = 1;
+    public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
     public static final int ALLOW_FULL_ONLY = 2;
     /**
      * Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
      * or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} if in the same profile group.
      * Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
      */
-    public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL = 3;
-    /**
-     * Requires {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES},
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}, or
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if in same profile group,
-     * otherwise {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. (so this is an extension
-     * to {@link #ALLOW_NON_FULL})
-     */
-    public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL = 4;
+    public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
 
     /**
      * Verify that calling app has access to the given provider.
@@ -350,7 +341,8 @@
     /** @see com.android.server.am.ActivityManagerService#monitor */
     public abstract void monitor();
 
-    /** Input dispatch timeout to a window, start the ANR process. */
+    /** Input dispatch timeout to a window, start the ANR process. Return the timeout extension,
+     * in milliseconds, or 0 to abort dispatch. */
     public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
     public abstract boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
             ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
@@ -457,7 +449,7 @@
     public abstract int broadcastIntent(Intent intent,
             IIntentReceiver resultTo,
             String[] requiredPermissions, boolean serialized,
-            int userId, int[] appIdWhitelist);
+            int userId, int[] appIdAllowList);
 
     /**
      * Add uid to the ActivityManagerService PendingStartActivityUids list.
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 5e05506..9833ed6 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -24,6 +24,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
+import android.annotation.UiContext;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -101,6 +102,7 @@
     private final WindowManager mWindowManager;
 
     @UnsupportedAppUsage
+    @UiContext
     final Context mContext;
     @UnsupportedAppUsage
     final Window mWindow;
@@ -158,7 +160,7 @@
      * @param context the context in which the dialog should run
      * @see android.R.styleable#Theme_dialogTheme
      */
-    public Dialog(@NonNull Context context) {
+    public Dialog(@UiContext @NonNull Context context) {
         this(context, 0, true);
     }
 
@@ -177,11 +179,12 @@
      * @param themeResId a style resource describing the theme to use for the
      *              window, or {@code 0} to use the default dialog theme
      */
-    public Dialog(@NonNull Context context, @StyleRes int themeResId) {
+    public Dialog(@UiContext @NonNull Context context, @StyleRes int themeResId) {
         this(context, themeResId, true);
     }
 
-    Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
+    Dialog(@UiContext @NonNull Context context, @StyleRes int themeResId,
+            boolean createContextThemeWrapper) {
         if (createContextThemeWrapper) {
             if (themeResId == Resources.ID_NULL) {
                 final TypedValue outValue = new TypedValue();
@@ -222,7 +225,7 @@
         mCancelMessage = cancelCallback;
     }
 
-    protected Dialog(@NonNull Context context, boolean cancelable,
+    protected Dialog(@UiContext @NonNull Context context, boolean cancelable,
             @Nullable OnCancelListener cancelListener) {
         this(context);
         mCancelable = cancelable;
@@ -234,7 +237,9 @@
      * 
      * @return Context The Context used by the Dialog.
      */
-    public final @NonNull Context getContext() {
+    @UiContext
+    @NonNull
+    public final Context getContext() {
         return mContext;
     }
 
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c5d343d..0a80ccc 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -26,6 +26,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UiContext;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -213,7 +214,6 @@
     private static final Object sSync = new Object[0];
     @UnsupportedAppUsage
     private static Globals sGlobals;
-
     private final Context mContext;
     private final boolean mWcgEnabled;
     private final ColorManagementProxy mCmProxy;
@@ -539,7 +539,8 @@
         }
     }
 
-    /*package*/ WallpaperManager(IWallpaperManager service, Context context, Handler handler) {
+    /*package*/ WallpaperManager(IWallpaperManager service, @UiContext Context context,
+            Handler handler) {
         mContext = context;
         if (service != null) {
             initGlobals(service, context.getMainLooper());
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index cb416c9..5f72bac 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiContext;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.os.Bundle;
@@ -42,6 +43,7 @@
  * @see Context#createWindowContext(int, Bundle)
  * @hide
  */
+@UiContext
 public class WindowContext extends ContextWrapper {
     private final WindowManagerImpl mWindowManager;
     private final IWindowManager mWms;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 8a6cc95..1345e66 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -109,7 +109,7 @@
 
 
     /**
-     * The app is whitelisted for some reason and the bucket cannot be changed.
+     * The app is exempted for some reason and the bucket cannot be changed.
      * {@hide}
      */
     @SystemApi
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index fa3df1d..fd60560 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1033,6 +1033,18 @@
     }
 
     /**
+     * Returns the anonymized hardware address of this BluetoothDevice. The first three octets
+     * will be suppressed for anonymization.
+     * <p> For example, "XX:XX:XX:AA:BB:CC".
+     *
+     * @return Anonymized bluetooth hardware address as string
+     * @hide
+     */
+    public String getAnonymizedAddress() {
+        return "XX:XX:XX" + getAddress().substring(8);
+    }
+
+    /**
      * Get the friendly Bluetooth name of the remote device.
      *
      * <p>The local adapter will automatically retrieve remote names when
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
index 2649fbe..cf9eeca 100644
--- a/core/java/android/companion/BluetoothDeviceFilter.java
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -142,6 +142,16 @@
     }
 
     @Override
+    public String toString() {
+        return "BluetoothDeviceFilter{"
+                + "mNamePattern=" + mNamePattern
+                + ", mAddress='" + mAddress + '\''
+                + ", mServiceUuids=" + mServiceUuids
+                + ", mServiceUuidMasks=" + mServiceUuidMasks
+                + '}';
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 60ecf64..33be50d 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1620,13 +1620,12 @@
      * Implementation when a caller has performed an insert on the content
      * provider, but that call has been rejected for the operation given
      * to {@link #setAppOps(int, int)}.  The default implementation simply
-     * returns a dummy URI that is the base URI with a 0 path element
-     * appended.
+     * returns a URI that is the base URI with a 0 path element appended.
      */
     public Uri rejectInsert(Uri uri, ContentValues values) {
         // If not allowed, we need to return some reasonable URI.  Maybe the
         // content provider should be responsible for this, but for now we
-        // will just return the base URI with a dummy '0' tagged on to it.
+        // will just return the base URI with a '0' tagged on to it.
         // You shouldn't be able to read if you can't write, anyway, so it
         // shouldn't matter much what is returned.
         return uri.buildUpon().appendPath("0").build();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2385712..16cdf23 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -21,6 +21,7 @@
 import android.annotation.CheckResult;
 import android.annotation.ColorInt;
 import android.annotation.ColorRes;
+import android.annotation.DisplayContext;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -33,6 +34,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.annotation.UiContext;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IApplicationThread;
@@ -3750,6 +3752,7 @@
      * @see #getSystemService(String)
      * @see android.view.WindowManager
      */
+    @UiContext
     public static final String WINDOW_SERVICE = "window";
 
     /**
@@ -3760,6 +3763,7 @@
      * @see #getSystemService(String)
      * @see android.view.LayoutInflater
      */
+    @UiContext
     public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
 
     /**
@@ -3932,6 +3936,7 @@
      *
      * @see #getSystemService(String)
      */
+    @UiContext
     public static final String WALLPAPER_SERVICE = "wallpaper";
 
     /**
@@ -5789,6 +5794,7 @@
      *
      * @return A {@link Context} for the display.
      */
+    @DisplayContext
     public abstract Context createDisplayContext(@NonNull Display display);
 
     /**
@@ -5853,7 +5859,9 @@
      * the current number of window contexts without adding any view by
      * {@link WindowManager#addView} <b>exceeds five</b>.
      */
-    public @NonNull Context createWindowContext(@WindowType int type, @Nullable Bundle options)  {
+    @UiContext
+    @NonNull
+    public Context createWindowContext(@WindowType int type, @Nullable Bundle options)  {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index b72eb04..8d0baa7 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -273,7 +273,7 @@
                     totalStats.numSyncs - totalStats.numSourceLocal - totalStats.numSourcePoll
                             - totalStats.numSourceOther
                             - totalStats.numSourceUser;
-            if (totalStats.numSourcePeriodic < 0) { // Sanity check.
+            if (totalStats.numSourcePeriodic < 0) { // Consistency check.
                 totalStats.numSourcePeriodic = 0;
             }
         } else {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index bd02210..31c77ee 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -963,7 +963,7 @@
     /** @hide */
     public static final int LOCK_TASK_LAUNCH_MODE_ALWAYS = 2;
     /** @hide */
-    public static final int LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED = 3;
+    public static final int LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED = 3;
 
     /** @hide */
     public static final String lockTaskLaunchModeToString(int lockTaskLaunchMode) {
@@ -974,8 +974,8 @@
                 return "LOCK_TASK_LAUNCH_MODE_NEVER";
             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
                 return "LOCK_TASK_LAUNCH_MODE_ALWAYS";
-            case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
-                return "LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED";
+            case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+                return "LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED";
             default:
                 return "unknown=" + lockTaskLaunchMode;
         }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index df9db27..bed7b26 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2075,7 +2075,8 @@
                 STAGED_SESSION_NO_ERROR,
                 STAGED_SESSION_VERIFICATION_FAILED,
                 STAGED_SESSION_ACTIVATION_FAILED,
-                STAGED_SESSION_UNKNOWN})
+                STAGED_SESSION_UNKNOWN,
+                STAGED_SESSION_OTHER_ERROR})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StagedSessionErrorCode{}
         /**
@@ -2101,6 +2102,12 @@
          */
         public static final int STAGED_SESSION_UNKNOWN = 3;
 
+        /**
+         * Constant indicating that a known error occurred while processing this staged session, but
+         * the error could not be matched to other categories.
+         */
+        public static final int STAGED_SESSION_OTHER_ERROR = 4;
+
         /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int sessionId;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 7c4692c..0efd883 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -219,7 +219,7 @@
      * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
      * The denial of service problem only comes into play when the pattern length gets
      * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
-     * are at most a few dozen bytes in length, paranoid application developers may
+     * are at most a few dozen bytes in length, cautious application developers may
      * want to reduce this parameter to something in the range of a few hundred
      * if they know that external users are able to generate arbitrary patterns.
      */
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c5a11abe..7250801 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -32,6 +32,7 @@
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiContext;
 import android.app.ActivityManager;
 import android.app.Dialog;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -258,6 +259,7 @@
  * @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation
  * @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation
  */
+@UiContext
 public class InputMethodService extends AbstractInputMethodService {
     static final String TAG = "InputMethodService";
     static final boolean DEBUG = false;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fbe6a50..b0d4497 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -743,6 +743,12 @@
         @UnsupportedAppUsage
         public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
 
+        /**
+         * Returns the proportion of power consumed by the System Service
+         * calls made by this UID.
+         */
+        public abstract double getProportionalSystemServiceUsage();
+
         public abstract ControllerActivityCounter getWifiControllerActivity();
         public abstract ControllerActivityCounter getBluetoothControllerActivity();
         public abstract ControllerActivityCounter getModemControllerActivity();
@@ -2882,6 +2888,17 @@
     public abstract int getDischargeAmountScreenDozeSinceCharge();
 
     /**
+     * Returns the approximate CPU time (in microseconds) spent by the system server handling
+     * incoming service calls from apps.
+     *
+     * @param cluster the index of the CPU cluster.
+     * @param step the index of the CPU speed. This is not the actual speed of the CPU.
+     * @see com.android.internal.os.PowerProfile#getNumCpuClusters()
+     * @see com.android.internal.os.PowerProfile#getNumSpeedStepsInCpuCluster(int)
+     */
+    public abstract long getSystemServiceTimeAtCpuSpeed(int cluster, int step);
+
+    /**
      * Returns the total, last, or current battery uptime in microseconds.
      *
      * @param curTime the elapsed realtime in microseconds.
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index bb8d4fe..3dce130 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -276,7 +276,7 @@
     }
 
     /**
-     * Create a dummy instance for testing.  All methods will fail unless
+     * Create an instance for testing. All methods will fail unless
      * overridden with an appropriate mock implementation.  To obtain a
      * functional instance, use {@link android.content.Context#getSystemService}.
      */
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 87e7043..70c924a 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1306,7 +1306,7 @@
 
     /** {@hide} */
     public static int translateModeStringToPosix(String mode) {
-        // Sanity check for invalid chars
+        // Quick check for invalid chars
         for (int i = 0; i < mode.length(); i++) {
             switch (mode.charAt(i)) {
                 case 'r':
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 1539b6e..a6b869d 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -570,7 +570,7 @@
         final ContentResolver contentResolver = context.getContentResolver();
         final List<String> angleAllowlist =
                 getGlobalSettingsString(contentResolver, bundle,
-                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST);
 
         if (DEBUG) Log.v(TAG, "ANGLE allowlist: " + angleAllowlist);
 
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 0ec4fb8..40c291f 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -16,6 +16,6 @@
 per-file PowerManagerInternal.java = michaelwr@google.com, santoscordon@google.com
 
 # Zygote
-per-file ZygoteProcess.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
+per-file ZygoteProcess.java = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
 
 per-file GraphicsEnvironment.java = chrisforbes@google.com, cnorthrop@google.com, lpy@google.com, timvp@google.com, zzyiwei@google.com
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 39038f5..ffede09 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -251,11 +251,11 @@
     private final Object mLock = new Object();
 
     /**
-     * List of exemptions to the API blacklist. These are prefix matches on the runtime format
+     * List of exemptions to the API deny list. These are prefix matches on the runtime format
      * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
      * list.
      */
-    private List<String> mApiBlacklistExemptions = Collections.emptyList();
+    private List<String> mApiDenylistExemptions = Collections.emptyList();
 
     /**
      * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
@@ -562,7 +562,7 @@
         "--preload-package",
         "--preload-app",
         "--start-child-zygote",
-        "--set-api-blacklist-exemptions",
+        "--set-api-denylist-exemptions",
         "--hidden-api-log-sampling-rate",
         "--hidden-api-statslog-sampling-rate",
         "--invoke-with"
@@ -922,20 +922,20 @@
     }
 
     /**
-     * Push hidden API blacklisting exemptions into the zygote process(es).
+     * Push hidden API deny-listing exemptions into the zygote process(es).
      *
      * <p>The list of exemptions will take affect for all new processes forked from the zygote after
      * this call.
      *
      * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
-     *        whitelisted/public APIs (i.e. allowed, no logging of usage).
+     *        allowed/public APIs (i.e. allowed, no logging of usage).
      */
-    public boolean setApiBlacklistExemptions(List<String> exemptions) {
+    public boolean setApiDenylistExemptions(List<String> exemptions) {
         synchronized (mLock) {
-            mApiBlacklistExemptions = exemptions;
-            boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
+            mApiDenylistExemptions = exemptions;
+            boolean ok = maybeSetApiDenylistExemptions(primaryZygoteState, true);
             if (ok) {
-                ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
+                ok = maybeSetApiDenylistExemptions(secondaryZygoteState, true);
             }
             return ok;
         }
@@ -972,32 +972,32 @@
     }
 
     @GuardedBy("mLock")
-    private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
+    private boolean maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty) {
         if (state == null || state.isClosed()) {
-            Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
+            Slog.e(LOG_TAG, "Can't set API denylist exemptions: no zygote connection");
             return false;
-        } else if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
+        } else if (!sendIfEmpty && mApiDenylistExemptions.isEmpty()) {
             return true;
         }
 
         try {
-            state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
+            state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1));
             state.mZygoteOutputWriter.newLine();
-            state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
+            state.mZygoteOutputWriter.write("--set-api-denylist-exemptions");
             state.mZygoteOutputWriter.newLine();
-            for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
-                state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
+            for (int i = 0; i < mApiDenylistExemptions.size(); ++i) {
+                state.mZygoteOutputWriter.write(mApiDenylistExemptions.get(i));
                 state.mZygoteOutputWriter.newLine();
             }
             state.mZygoteOutputWriter.flush();
             int status = state.mZygoteInputStream.readInt();
             if (status != 0) {
-                Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
+                Slog.e(LOG_TAG, "Failed to set API denylist exemptions; status " + status);
             }
             return true;
         } catch (IOException ioe) {
-            Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
-            mApiBlacklistExemptions = Collections.emptyList();
+            Slog.e(LOG_TAG, "Failed to set API denylist exemptions", ioe);
+            mApiDenylistExemptions = Collections.emptyList();
             return false;
         }
     }
@@ -1054,7 +1054,7 @@
             primaryZygoteState =
                     ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
 
-            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
+            maybeSetApiDenylistExemptions(primaryZygoteState, false);
             maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
         }
     }
@@ -1069,7 +1069,7 @@
                     ZygoteState.connect(mZygoteSecondarySocketAddress,
                             mUsapPoolSecondarySocketAddress);
 
-            maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
+            maybeSetApiDenylistExemptions(secondaryZygoteState, false);
             maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
         }
     }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cfe7edd..5acc11a8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8728,16 +8728,6 @@
                 = "bubble_important_conversations";
 
         /**
-         * When enabled, notifications the notification assistant service has modified will show an
-         * indicator. When tapped, this indicator will describe the adjustment made and solicit
-         * feedback. This flag will also add a "automatic" option to the long press menu.
-         *
-         * The value 1 - enable, 0 - disable
-         * @hide
-         */
-        public static final String NOTIFICATION_FEEDBACK_ENABLED = "notification_feedback_enabled";
-
-        /**
          * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
          * swipe).
          *
@@ -12338,8 +12328,8 @@
          * List of package names that should check ANGLE rules
          * @hide
          */
-        public static final String GLOBAL_SETTINGS_ANGLE_WHITELIST =
-                "angle_whitelist";
+        public static final String GLOBAL_SETTINGS_ANGLE_ALLOWLIST =
+                "angle_allowlist";
 
         /**
          * Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
@@ -14047,6 +14037,16 @@
                 "notification_snooze_options";
 
         /**
+         * When enabled, notifications the notification assistant service has modified will show an
+         * indicator. When tapped, this indicator will describe the adjustment made and solicit
+         * feedback. This flag will also add a "automatic" option to the long press menu.
+         *
+         * The value 1 - enable, 0 - disable
+         * @hide
+         */
+        public static final String NOTIFICATION_FEEDBACK_ENABLED = "notification_feedback_enabled";
+
+        /**
          * Settings key for the ratio of notification dismissals to notification views - one of the
          * criteria for showing the notification blocking helper.
          *
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 0a47032..a720601 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -26,10 +26,8 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.CallState;
 import android.telephony.Annotation.DataActivityType;
-import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.DisconnectCauses;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.Annotation.PreciseCallStates;
@@ -37,7 +35,6 @@
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.SrvccState;
-import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 import android.util.Log;
@@ -402,17 +399,16 @@
      * @param subId for which data connection state changed.
      * @param slotIndex for which data connections state changed. Can be derived from subId except
      * when subId is invalid.
-     * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
      * @param preciseState the PreciseDataConnectionState
      *
-     * @see android.telephony.PreciseDataConnection
+     * @see PreciseDataConnectionState
      * @see TelephonyManager#DATA_DISCONNECTED
      */
     public void notifyDataConnectionForSubscriber(int slotIndex, int subId,
-            @ApnType int apnType, @Nullable PreciseDataConnectionState preciseState) {
+            @NonNull PreciseDataConnectionState preciseState) {
         try {
             sRegistry.notifyDataConnectionForSubscriber(
-                    slotIndex, subId, apnType, preciseState);
+                    slotIndex, subId, preciseState);
         } catch (RemoteException ex) {
             // system process is dead
         }
@@ -612,25 +608,6 @@
     }
 
     /**
-     * Notify precise data connection failed cause on certain subscription.
-     *
-     * @param subId for which data connection failed.
-     * @param slotIndex for which data conenction failed. Can be derived from subId except when
-     * subId is invalid.
-     * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
-     * @param apn the APN {@link ApnSetting#getApnName()} of this data connection.
-     * @param failCause data fail cause.
-     */
-    public void notifyPreciseDataConnectionFailed(int subId, int slotIndex, @ApnType int apnType,
-            @Nullable String apn, @DataFailureCause int failCause) {
-        try {
-            sRegistry.notifyPreciseDataConnectionFailed(slotIndex, subId, apnType, apn, failCause);
-        } catch (RemoteException ex) {
-            // system process is dead
-        }
-    }
-
-    /**
      * Notify single Radio Voice Call Continuity (SRVCC) state change for the currently active call
      * on certain subscription.
      *
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
index cbe3734..aa70d07 100644
--- a/core/java/android/util/proto/ProtoInputStream.java
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -96,7 +96,7 @@
     private byte mState = 0;
 
     /**
-     * Keeps track of the currently read nested Objects, for end object sanity checking and debug
+     * Keeps track of the currently read nested Objects, for end object checking and debug
      */
     private ArrayList<Long> mExpectedObjectTokenStack = null;
 
@@ -513,7 +513,7 @@
                     (int) fieldId, getOffset() + messageSize));
         }
 
-        // Sanity check
+        // Validation check
         if (mDepth > 0
                 && getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth))
                 > getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth - 1))) {
@@ -536,7 +536,7 @@
      * @param token - token
      */
     public void end(long token) {
-        // Sanity check to make sure user is keeping track of their embedded messages
+        // Make sure user is keeping track of their embedded messages
         if (mExpectedObjectTokenStack.get(mDepth) != token) {
             throw new ProtoParseException(
                     "end token " + token + " does not match current message token "
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 5fcd38e..afca4ab 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -59,10 +59,10 @@
  * cache the size, and then write the size-prefixed buffers.
  *
  * We are trying to avoid too much generated code here, but this class still
- * needs to have a somewhat sane API.  We can't have the multiple passes be
- * done by the calling code.  In addition, we want to avoid the memory high
- * water mark of duplicating all of the values into the traditional in-memory
- * Message objects. We need to find another way.
+ * needs to have API.  We can't have the multiple passes be done by the
+ * calling code.  In addition, we want to avoid the memory high water mark
+ * of duplicating all of the values into the traditional in-memory Message
+ * objects. We need to find another way.
  *
  * So what we do here is to let the calling code write the data into a
  * byte[] (actually a collection of them wrapped in the EncodedBuffer class),
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 55c527b..8a72218 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -25,6 +25,7 @@
 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP;
 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
 
+import android.annotation.UiContext;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Build;
@@ -393,7 +394,7 @@
      *
      * @throws NullPointerException if {@code listener} is null.
      */
-    public GestureDetector(Context context, OnGestureListener listener) {
+    public GestureDetector(@UiContext Context context, OnGestureListener listener) {
         this(context, listener, null);
     }
 
@@ -412,7 +413,8 @@
      *
      * @throws NullPointerException if {@code listener} is null.
      */
-    public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
+    public GestureDetector(@UiContext Context context, OnGestureListener listener,
+            Handler handler) {
         if (handler != null) {
             mHandler = new GestureHandler(handler);
         } else {
@@ -442,12 +444,12 @@
      *
      * @throws NullPointerException if {@code listener} is null.
      */
-    public GestureDetector(Context context, OnGestureListener listener, Handler handler,
+    public GestureDetector(@UiContext Context context, OnGestureListener listener, Handler handler,
             boolean unused) {
         this(context, listener, handler);
     }
 
-    private void init(Context context) {
+    private void init(@UiContext Context context) {
         if (mListener == null) {
             throw new NullPointerException("OnGestureListener must not be null");
         }
diff --git a/core/java/android/view/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java
index 3d05e2a..108345e 100644
--- a/core/java/android/view/InputApplicationHandle.java
+++ b/core/java/android/view/InputApplicationHandle.java
@@ -34,7 +34,7 @@
     public String name;
 
     // Dispatching timeout.
-    public long dispatchingTimeoutNanos;
+    public long dispatchingTimeoutMillis;
 
     public final IBinder token;
 
@@ -46,7 +46,7 @@
 
     public InputApplicationHandle(InputApplicationHandle handle) {
         this.token = handle.token;
-        this.dispatchingTimeoutNanos = handle.dispatchingTimeoutNanos;
+        this.dispatchingTimeoutMillis = handle.dispatchingTimeoutMillis;
         this.name = handle.name;
     }
 
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index a7e0305..e341845 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -50,7 +50,7 @@
     public int layoutParamsType;
 
     // Dispatching timeout.
-    public long dispatchingTimeoutNanos;
+    public long dispatchingTimeoutMillis;
 
     // Window frame.
     public int frameLeft;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 1afe11e..b925b49 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UiContext;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -94,6 +95,7 @@
      * {@hide}
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UiContext
     protected final Context mContext;
 
     // these are optional, set by the caller
@@ -277,7 +279,7 @@
     /**
      * Obtains the LayoutInflater from the given context.
      */
-    public static LayoutInflater from(Context context) {
+    public static LayoutInflater from(@UiContext Context context) {
         LayoutInflater LayoutInflater =
                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         if (LayoutInflater == null) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index eaa7eaf..50ed00c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -89,13 +89,10 @@
     private static native void nativeWriteToParcel(long nativeObject, Parcel out);
     private static native void nativeRelease(long nativeObject);
     private static native void nativeDisconnect(long nativeObject);
-
-    private static native ScreenshotHardwareBuffer nativeScreenshot(IBinder displayToken,
-            Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation,
-            boolean captureSecureLayers);
-    private static native ScreenshotHardwareBuffer nativeCaptureLayers(IBinder displayToken,
-            long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects,
-            int format);
+    private static native ScreenshotHardwareBuffer nativeCaptureDisplay(
+            DisplayCaptureArgs captureArgs);
+    private static native ScreenshotHardwareBuffer nativeCaptureLayers(
+            LayerCaptureArgs captureArgs);
     private static native long nativeMirrorSurface(long mirrorOfObject);
     private static native long nativeCreateTransaction();
     private static native long nativeGetNativeTransactionFinalizer();
@@ -572,7 +569,8 @@
         * Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
         * @param hardwareBuffer The existing HardwareBuffer object
         * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
-        * @param containsSecureLayer Indicates whether this graphic buffer contains captured contents
+        * @param containsSecureLayers Indicates whether this graphic buffer contains captured
+        *                             contents
         *        of secure layers, in which case the screenshot should not be persisted.
         */
         private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
@@ -662,14 +660,14 @@
             /**
              * Each sub class should return itself to allow the builder to chain properly
              */
-            public abstract T getThis();
+            abstract T getThis();
         }
     }
 
     /**
      * The arguments class used to make display capture requests.
      *
-     * @see #nativeScreenshot(IBinder, Rect, int, int, boolean, int, boolean)
+     * @see #nativeCaptureDisplay(DisplayCaptureArgs)
      * @hide
      */
     public static class DisplayCaptureArgs extends CaptureArgs {
@@ -759,7 +757,7 @@
             }
 
             @Override
-            public Builder getThis() {
+            Builder getThis() {
                 return this;
             }
         }
@@ -768,7 +766,7 @@
     /**
      * The arguments class used to make layer capture requests.
      *
-     * @see #nativeCaptureLayers(IBinder, long, Rect, float, long[], int)
+     * @see #nativeCaptureLayers(LayerCaptureArgs)
      * @hide
      */
     public static class LayerCaptureArgs extends CaptureArgs {
@@ -780,9 +778,13 @@
             super(builder);
             mChildrenOnly = builder.mChildrenOnly;
             mNativeLayer = builder.mLayer.mNativeObject;
-            mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
-            for (int i = 0; i < builder.mExcludeLayers.length; i++) {
-                mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+            if (builder.mExcludeLayers != null) {
+                mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
+                for (int i = 0; i < builder.mExcludeLayers.length; i++) {
+                    mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+                }
+            } else {
+                mNativeExcludeLayers = null;
             }
         }
 
@@ -837,7 +839,7 @@
             }
 
             @Override
-            public Builder getThis() {
+            Builder getThis() {
                 return this;
             }
 
@@ -2293,8 +2295,14 @@
             throw new IllegalArgumentException("displayToken must not be null");
         }
 
-        return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
-                false /* captureSecureLayers */);
+        DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display)
+                .setSourceCrop(sourceCrop)
+                .setSize(width, height)
+                .setUseIdentityTransform(useIdentityTransform)
+                .setRotation(rotation)
+                .build();
+
+        return nativeCaptureDisplay(captureArgs);
     }
 
     /**
@@ -2314,8 +2322,15 @@
             throw new IllegalArgumentException("displayToken must not be null");
         }
 
-        return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
-                true /* captureSecureLayers */);
+        DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display)
+                .setSourceCrop(sourceCrop)
+                .setSize(width, height)
+                .setUseIdentityTransform(useIdentityTransform)
+                .setRotation(rotation)
+                .setCaptureSecureLayers(true)
+                .build();
+
+        return nativeCaptureDisplay(captureArgs);
     }
 
     private static void rotateCropForSF(Rect crop, int rot) {
@@ -2365,24 +2380,30 @@
      */
     public static ScreenshotHardwareBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
             float frameScale, int format) {
-        final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
-        return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null,
-                format);
+        LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+                .setSourceCrop(sourceCrop)
+                .setFrameScale(frameScale)
+                .setPixelFormat(format)
+                .build();
+
+        return nativeCaptureLayers(captureArgs);
     }
 
     /**
-     * Like {@link captureLayers} but with an array of layer handles to exclude.
+     * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
+     * handles to exclude.
      * @hide
      */
     public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
             Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude) {
-        final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
-        long[] nativeExcludeObjects = new long[exclude.length];
-        for (int i = 0; i < exclude.length; i++) {
-            nativeExcludeObjects[i] = exclude[i].mNativeObject;
-        }
-        return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale,
-                nativeExcludeObjects, PixelFormat.RGBA_8888);
+        LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+                .setSourceCrop(sourceCrop)
+                .setFrameScale(frameScale)
+                .setPixelFormat(format)
+                .setExcludeLayers(exclude)
+                .build();
+
+        return nativeCaptureLayers(captureArgs);
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e951156..8917821 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -43,6 +43,7 @@
 import android.annotation.Size;
 import android.annotation.StyleRes;
 import android.annotation.TestApi;
+import android.annotation.UiContext;
 import android.annotation.UiThread;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.AutofillOptions;
@@ -952,8 +953,7 @@
 
     /**
      * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow.
-     * Currently zero size SurfaceControl cannot be created thus we create a dummy 1x1 surface
-     * instead.
+     * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead.
      */
     private static boolean sAcceptZeroSizeDragShadow;
 
@@ -4910,6 +4910,7 @@
      */
     @ViewDebug.ExportedProperty(deepExport = true)
     @UnsupportedAppUsage
+    @UiContext
     protected Context mContext;
 
     @UnsupportedAppUsage
@@ -15071,6 +15072,7 @@
      * @return The view's Context.
      */
     @ViewDebug.CapturedViewProperty
+    @UiContext
     public final Context getContext() {
         return mContext;
     }
@@ -23356,7 +23358,7 @@
      *            displaying, else return the result of calling through to the
      *            super class.
      *
-     * @return boolean If true than the Drawable is being displayed in the
+     * @return boolean If true then the Drawable is being displayed in the
      *         view; else false and it is not allowed to animate.
      *
      * @see #unscheduleDrawable(android.graphics.drawable.Drawable)
@@ -30023,7 +30025,7 @@
 
     /**
      * Dump all private flags in readable format, useful for documentation and
-     * sanity checking.
+     * consistency checking.
      */
     private static void dumpFlags() {
         final HashMap<String, String> found = Maps.newHashMap();
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index ffeeb80..ccf1fb0 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -20,6 +20,7 @@
 
 import android.annotation.FloatRange;
 import android.annotation.TestApi;
+import android.annotation.UiContext;
 import android.app.Activity;
 import android.app.AppGlobals;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -391,7 +392,7 @@
      * @see #get(android.content.Context)
      * @see android.util.DisplayMetrics
      */
-    private ViewConfiguration(Context context) {
+    private ViewConfiguration(@UiContext Context context) {
         mConstructedWithContext = true;
         final Resources res = context.getResources();
         final DisplayMetrics metrics = res.getDisplayMetrics();
@@ -498,7 +499,8 @@
      *                be {@link Activity} or other {@link Context} created with
      *                {@link Context#createWindowContext(int, Bundle)}.
      */
-    public static ViewConfiguration get(Context context) {
+
+    public static ViewConfiguration get(@UiContext Context context) {
         if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
             final String errorMessage = "Tried to access UI constants from a non-visual Context:"
                     + context;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2a2d1e6..64ddb2f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -64,6 +64,7 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiContext;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.ResourcesManager;
@@ -349,6 +350,7 @@
     @GuardedBy("mWindowCallbacks")
     final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
     @UnsupportedAppUsage
+    @UiContext
     public final Context mContext;
 
     @UnsupportedAppUsage
@@ -719,11 +721,11 @@
                 false /* useSfChoreographer */);
     }
 
-    public ViewRootImpl(Context context, Display display, IWindowSession session) {
+    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
         this(context, display, session, false /* useSfChoreographer */);
     }
 
-    public ViewRootImpl(Context context, Display display, IWindowSession session,
+    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
             boolean useSfChoreographer) {
         mContext = context;
         mWindowSession = session;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 446e7aa..1dbf37a 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -27,6 +27,7 @@
 import android.annotation.StyleRes;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.annotation.UiContext;
 import android.app.WindowConfiguration;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -280,6 +281,7 @@
     public static final int DECOR_CAPTION_SHADE_DARK = 2;
 
     @UnsupportedAppUsage
+    @UiContext
     private final Context mContext;
 
     @UnsupportedAppUsage
@@ -722,7 +724,7 @@
     }
 
 
-    public Window(Context context) {
+    public Window(@UiContext Context context) {
         mContext = context;
         mFeatures = mLocalFeatures = getDefaultFeatures(context);
     }
@@ -733,6 +735,7 @@
      *
      * @return Context The Context that was supplied to the constructor.
      */
+    @UiContext
     public final Context getContext() {
         return mContext;
     }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index cf4315f..7923ff0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -347,6 +347,7 @@
             TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE,
             TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION,
             TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER,
+            TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionFlags {}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index b4561c5..27fbfb6 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -25,6 +25,7 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 
 import android.annotation.NonNull;
+import android.annotation.UiContext;
 import android.app.ResourcesManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -69,6 +70,7 @@
 public final class WindowManagerImpl implements WindowManager {
     @UnsupportedAppUsage
     private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
+    @UiContext
     @VisibleForTesting
     public final Context mContext;
     private final Window mParentWindow;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 708e277..2d0f05e 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1768,7 +1768,7 @@
      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
      *   and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
      *   the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
-     *   flag when configuring their {@link android.accessibilityservice.AccessibilityService}.
+     *   flag when configuring the {@link android.accessibilityservice.AccessibilityService}.
      * </p>
      * <p>
      * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another
@@ -3206,7 +3206,7 @@
      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
      *   and in order to report the source view id of an {@link AccessibilityNodeInfo} the
      *   client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
-     *   flag when configuring their {@link android.accessibilityservice.AccessibilityService}.
+     *   flag when configuring the {@link android.accessibilityservice.AccessibilityService}.
      * </p>
 
      * @return The id resource name.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 793d940..f6671d8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -22,6 +22,7 @@
 import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
 import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION;
 
+import android.annotation.DisplayContext;
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1193,7 +1194,7 @@
      * @hide
      */
     @NonNull
-    public static InputMethodManager forContext(Context context) {
+    public static InputMethodManager forContext(@DisplayContext Context context) {
         final int displayId = context.getDisplayId();
         // For better backward compatibility, we always use Looper.getMainLooper() for the default
         // display case.
diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING
index f089f48..df3024e 100644
--- a/core/java/android/widget/TEST_MAPPING
+++ b/core/java/android/widget/TEST_MAPPING
@@ -17,6 +17,45 @@
         }
       ],
       "file_patterns": ["Toast\\.java"]
+    },
+    {
+      "name": "CtsAutoFillServiceTestCases",
+      "options": [
+        {
+          "include-filter": "android.autofillservice.cts.LoginActivityTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+        }
+      ]
+    },
+    {
+      "name": "CtsAutoFillServiceTestCases",
+      "options": [
+        {
+          "include-filter": "android.autofillservice.cts.AutofillValueTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsAutoFillServiceTestCases",
+      "options": [
+        {
+          "include-filter": "android.autofillservice.cts.CheckoutActivityTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+        }
+      ]
     }
   ]
 }
diff --git a/core/java/android/widget/inline/TEST_MAPPING b/core/java/android/widget/inline/TEST_MAPPING
new file mode 100644
index 0000000..0baad5c
--- /dev/null
+++ b/core/java/android/widget/inline/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAutoFillServiceTestCases",
+      "options": [
+        {
+          "include-filter": "android.autofillservice.cts.inline"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index b3ea118..2620ba0 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -129,6 +129,7 @@
     public double videoPowerMah;
     public double wakeLockPowerMah;
     public double wifiPowerMah;
+    public double systemServiceCpuPowerMah;
 
     //                           ****************
     // This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto)
@@ -242,6 +243,7 @@
         videoPowerMah += other.videoPowerMah;
         proportionalSmearMah += other.proportionalSmearMah;
         totalSmearedPowerMah += other.totalSmearedPowerMah;
+        systemServiceCpuPowerMah += other.systemServiceCpuPowerMah;
     }
 
     /**
@@ -253,7 +255,8 @@
     public double sumPower() {
         totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
                 sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
-                flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah;
+                flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah
+                + systemServiceCpuPowerMah;
         totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah;
 
         return totalPowerMah;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index b131ab8..3dfa3c3 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -133,6 +133,7 @@
     private double mMaxDrainedPower;
 
     PowerCalculator mCpuPowerCalculator;
+    SystemServicePowerCalculator mSystemServicePowerCalculator;
     PowerCalculator mWakelockPowerCalculator;
     MobileRadioPowerCalculator mMobileRadioPowerCalculator;
     PowerCalculator mWifiPowerCalculator;
@@ -396,6 +397,11 @@
         }
         mCpuPowerCalculator.reset();
 
+        if (mSystemServicePowerCalculator == null) {
+            mSystemServicePowerCalculator = new SystemServicePowerCalculator(mPowerProfile, mStats);
+        }
+        mSystemServicePowerCalculator.reset();
+
         if (mMemoryPowerCalculator == null) {
             mMemoryPowerCalculator = new MemoryPowerCalculator(mPowerProfile);
         }
@@ -588,6 +594,8 @@
             mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
                     mStatsType);
             mMediaPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mSystemServicePowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
+                    mStatsType);
 
             final double totalPower = app.sumPower();
             if (DEBUG && totalPower != 0) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 58ba16b..8498151 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -144,6 +144,7 @@
     private static final boolean DEBUG = false;
     public static final boolean DEBUG_ENERGY = false;
     private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
+    private static final boolean DEBUG_BINDER_STATS = true;
     private static final boolean DEBUG_MEMORY = false;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
@@ -154,7 +155,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 186 + (USE_OLD_HISTORY ? 1000 : 0);
+    static final int VERSION = 187 + (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
@@ -218,10 +219,13 @@
             new KernelCpuUidClusterTimeReader(true);
     @VisibleForTesting
     protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
+    @VisibleForTesting
+    protected SystemServerCpuThreadReader mSystemServerCpuThreadReader;
 
     private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
             = new KernelMemoryBandwidthStats();
     private final LongSparseArray<SamplingTimer> mKernelMemoryStats = new LongSparseArray<>();
+
     public LongSparseArray<SamplingTimer> getKernelMemoryStats() {
         return mKernelMemoryStats;
     }
@@ -267,6 +271,7 @@
 
     /** Container for Rail Energy Data stats. */
     private final RailStats mTmpRailStats = new RailStats();
+
     /**
      * Use a queue to delay removing UIDs from {@link KernelCpuUidUserSysTimeReader},
      * {@link KernelCpuUidActiveTimeReader}, {@link KernelCpuUidClusterTimeReader},
@@ -1007,6 +1012,16 @@
 
     private long[] mCpuFreqs;
 
+    /**
+     * Times spent by the system server threads grouped by cluster and CPU speed.
+     */
+    private LongSamplingCounter[][] mSystemServerThreadCpuTimesUs;
+
+    /**
+     * Times spent by the system server threads handling incoming binder requests.
+     */
+    private LongSamplingCounter[][] mBinderThreadCpuTimesUs;
+
     @VisibleForTesting
     protected PowerProfile mPowerProfile;
 
@@ -6131,10 +6146,77 @@
      * the power consumption to the calling app.
      */
     public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
-            Collection<BinderCallsStats.CallStat> callStats) {
+            Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
         synchronized (this) {
             getUidStatsLocked(workSourceUid).noteBinderCallStatsLocked(incrementalCallCount,
                     callStats);
+            mSystemServerCpuThreadReader.setBinderThreadNativeTids(binderThreadNativeTids);
+        }
+    }
+
+    /**
+     * Estimates the proportion of system server CPU activity handling incoming binder calls
+     * that can be attributed to each app
+     */
+    @VisibleForTesting
+    public void updateSystemServiceCallStats() {
+        // Start off by computing the average duration of recorded binder calls,
+        // regardless of which binder or transaction. We will use this as a fallback
+        // for calls that were not sampled at all.
+        int totalRecordedCallCount = 0;
+        long totalRecordedCallTimeMicros = 0;
+        for (int i = 0; i < mUidStats.size(); i++) {
+            Uid uid = mUidStats.valueAt(i);
+            ArraySet<BinderCallStats> binderCallStats = uid.mBinderCallStats;
+            for (int j = binderCallStats.size() - 1; j >= 0; j--) {
+                BinderCallStats stats = binderCallStats.valueAt(j);
+                totalRecordedCallCount += stats.recordedCallCount;
+                totalRecordedCallTimeMicros += stats.recordedCpuTimeMicros;
+            }
+        }
+
+        long totalSystemServiceTimeMicros = 0;
+
+        // For every UID, use recorded durations of sampled binder calls to estimate
+        // the total time the system server spent handling requests from this UID.
+        for (int i = 0; i < mUidStats.size(); i++) {
+            Uid uid = mUidStats.valueAt(i);
+
+            long totalTimeForUid = 0;
+            int totalCallCountForUid = 0;
+            ArraySet<BinderCallStats> binderCallStats = uid.mBinderCallStats;
+            for (int j = binderCallStats.size() - 1; j >= 0; j--) {
+                BinderCallStats stats = binderCallStats.valueAt(j);
+                totalCallCountForUid += stats.callCount;
+                if (stats.recordedCallCount > 0) {
+                    totalTimeForUid +=
+                            stats.callCount * stats.recordedCpuTimeMicros / stats.recordedCallCount;
+                } else if (totalRecordedCallCount > 0) {
+                    totalTimeForUid +=
+                            stats.callCount * totalRecordedCallTimeMicros / totalRecordedCallCount;
+                }
+            }
+
+            if (totalCallCountForUid < uid.mBinderCallCount && totalRecordedCallCount > 0) {
+                // Estimate remaining calls, which were not tracked because of binder call
+                // stats sampling
+                totalTimeForUid +=
+                        (uid.mBinderCallCount - totalCallCountForUid) * totalRecordedCallTimeMicros
+                                / totalRecordedCallCount;
+            }
+
+            uid.mSystemServiceTimeUs = totalTimeForUid;
+            totalSystemServiceTimeMicros += totalTimeForUid;
+        }
+
+        for (int i = 0; i < mUidStats.size(); i++) {
+            Uid uid = mUidStats.valueAt(i);
+            if (totalSystemServiceTimeMicros > 0) {
+                uid.mProportionalSystemServiceUsage =
+                        (double) uid.mSystemServiceTimeUs / totalSystemServiceTimeMicros;
+            } else {
+                uid.mProportionalSystemServiceUsage = 0;
+            }
         }
     }
 
@@ -6583,7 +6665,7 @@
     /**
      * Accumulates stats for a specific binder transaction.
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    @VisibleForTesting
     protected static class BinderCallStats {
         static final Comparator<BinderCallStats> COMPARATOR =
                 Comparator.comparing(BinderCallStats::getClassName)
@@ -6822,6 +6904,16 @@
          */
         private final ArraySet<BinderCallStats> mBinderCallStats = new ArraySet<>();
 
+        /**
+         * Estimated total time spent by the system server handling requests from this uid.
+         */
+        private long mSystemServiceTimeUs;
+
+        /**
+         * Estimated proportion of system server binder call CPU cost for this uid.
+         */
+        private double mProportionalSystemServiceUsage;
+
         public Uid(BatteryStatsImpl bsi, int uid) {
             mBsi = bsi;
             mUid = uid;
@@ -6899,7 +6991,6 @@
             return nullIfAllZeros(mCpuClusterTimesMs, STATS_SINCE_CHARGED);
         }
 
-
         @Override
         public long[] getCpuFreqTimes(int which, int procState) {
             if (which < 0 || which >= NUM_PROCESS_STATE) {
@@ -6934,10 +7025,16 @@
             return mBinderCallCount;
         }
 
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
         public ArraySet<BinderCallStats> getBinderCallStats() {
             return mBinderCallStats;
         }
 
+        @Override
+        public  double getProportionalSystemServiceUsage() {
+            return mProportionalSystemServiceUsage;
+        }
+
         public void addIsolatedUid(int isolatedUid) {
             if (mChildUids == null) {
                 mChildUids = new IntArray();
@@ -8029,9 +8126,12 @@
             mBinderCallCount = 0;
             mBinderCallStats.clear();
 
+            mProportionalSystemServiceUsage = 0;
+
             mLastStepUserTime = mLastStepSystemTime = 0;
             mCurStepUserTime = mCurStepSystemTime = 0;
 
+
             return !active;
         }
 
@@ -8373,28 +8473,7 @@
             mUserCpuTime.writeToParcel(out);
             mSystemCpuTime.writeToParcel(out);
 
-            if (mCpuClusterSpeedTimesUs != null) {
-                out.writeInt(1);
-                out.writeInt(mCpuClusterSpeedTimesUs.length);
-                for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeedTimesUs) {
-                    if (cpuSpeeds != null) {
-                        out.writeInt(1);
-                        out.writeInt(cpuSpeeds.length);
-                        for (LongSamplingCounter c : cpuSpeeds) {
-                            if (c != null) {
-                                out.writeInt(1);
-                                c.writeToParcel(out);
-                            } else {
-                                out.writeInt(0);
-                            }
-                        }
-                    } else {
-                        out.writeInt(0);
-                    }
-                }
-            } else {
-                out.writeInt(0);
-            }
+            mBsi.writeCpuSpeedCountersToParcel(out, mCpuClusterSpeedTimesUs);
 
             LongSamplingCounterArray.writeToParcel(out, mCpuFreqTimeMs);
             LongSamplingCounterArray.writeToParcel(out, mScreenOffCpuFreqTimeMs);
@@ -8432,6 +8511,7 @@
             } else {
                 out.writeInt(0);
             }
+            out.writeDouble(mProportionalSystemServiceUsage);
         }
 
         void readJobCompletionsFromParcelLocked(Parcel in) {
@@ -8692,36 +8772,7 @@
             mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
             mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
 
-            if (in.readInt() != 0) {
-                int numCpuClusters = in.readInt();
-                if (mBsi.mPowerProfile != null && mBsi.mPowerProfile.getNumCpuClusters() != numCpuClusters) {
-                    throw new ParcelFormatException("Incompatible number of cpu clusters");
-                }
-
-                mCpuClusterSpeedTimesUs = new LongSamplingCounter[numCpuClusters][];
-                for (int cluster = 0; cluster < numCpuClusters; cluster++) {
-                    if (in.readInt() != 0) {
-                        int numSpeeds = in.readInt();
-                        if (mBsi.mPowerProfile != null &&
-                                mBsi.mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
-                            throw new ParcelFormatException("Incompatible number of cpu speeds");
-                        }
-
-                        final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
-                        mCpuClusterSpeedTimesUs[cluster] = cpuSpeeds;
-                        for (int speed = 0; speed < numSpeeds; speed++) {
-                            if (in.readInt() != 0) {
-                                cpuSpeeds[speed] = new LongSamplingCounter(
-                                        mBsi.mOnBatteryTimeBase, in);
-                            }
-                        }
-                    } else {
-                        mCpuClusterSpeedTimesUs[cluster] = null;
-                    }
-                }
-            } else {
-                mCpuClusterSpeedTimesUs = null;
-            }
+            mCpuClusterSpeedTimesUs = mBsi.readCpuSpeedCountersFromParcel(in);
 
             mCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(in, mBsi.mOnBatteryTimeBase);
             mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(
@@ -8762,6 +8813,8 @@
             } else {
                 mWifiRadioApWakeupCount = null;
             }
+
+            mProportionalSystemServiceUsage = in.readDouble();
         }
 
         public void noteJobsDeferredLocked(int numDeferred, long sinceLast) {
@@ -9904,7 +9957,6 @@
             UserInfoProvider userInfoProvider) {
         init(clocks);
 
-
         if (systemDir == null) {
             mStatsFile = null;
             mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
@@ -10046,6 +10098,8 @@
             firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
         }
 
+        mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+
         if (mEstimatedBatteryCapacity == -1) {
             // Initialize the estimated battery capacity to a known preset one.
             mEstimatedBatteryCapacity = (int) mPowerProfile.getBatteryCapacity();
@@ -10726,6 +10780,9 @@
 
         mTmpRailStats.reset();
 
+        resetIfNotNull(mSystemServerThreadCpuTimesUs, false);
+        resetIfNotNull(mBinderThreadCpuTimesUs, false);
+
         mLastHistoryStepDetails = null;
         mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
         mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
@@ -10853,7 +10910,7 @@
         return null;
     }
 
-   /**
+    /**
      * Distribute WiFi energy info and network traffic to apps.
      * @param info The energy information from the WiFi controller.
      */
@@ -11772,6 +11829,7 @@
             for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
                 mKernelCpuSpeedReaders[cluster].readDelta();
             }
+            mSystemServerCpuThreadReader.readDelta();
             return;
         }
 
@@ -11791,6 +11849,87 @@
             readKernelUidCpuClusterTimesLocked(onBattery);
             mNumAllUidCpuTimeReads += 2;
         }
+
+        updateSystemServerThreadStats();
+    }
+
+    /**
+     * Estimates the proportion of the System Server CPU activity (per cluster per speed)
+     * spent on handling incoming binder calls.
+     */
+    @VisibleForTesting
+    public void updateSystemServerThreadStats() {
+        // There are some simplifying assumptions made in this algorithm
+        // 1) We assume that if a thread handles incoming binder calls, all of its activity
+        //    is spent doing that.  Most incoming calls are handled by threads allocated
+        //    by the native layer in the binder thread pool, so this assumption is reasonable.
+        // 2) We use the aggregate CPU time spent in different threads as a proxy for the CPU
+        //    cost. In reality, in multi-core CPUs, the CPU cost may not be linearly
+        //    affected by additional threads.
+
+        SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+                    mSystemServerCpuThreadReader.readDelta();
+
+        int index = 0;
+        int numCpuClusters = mPowerProfile.getNumCpuClusters();
+        if (mSystemServerThreadCpuTimesUs == null) {
+            mSystemServerThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
+            mBinderThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
+        }
+        for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+            int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+            if (mSystemServerThreadCpuTimesUs[cluster] == null) {
+                mSystemServerThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
+                mBinderThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
+                for (int speed = 0; speed < numSpeeds; speed++) {
+                    mSystemServerThreadCpuTimesUs[cluster][speed] =
+                            new LongSamplingCounter(mOnBatteryTimeBase);
+                    mBinderThreadCpuTimesUs[cluster][speed] =
+                            new LongSamplingCounter(mOnBatteryTimeBase);
+                }
+            }
+            for (int speed = 0; speed < numSpeeds; speed++) {
+                mSystemServerThreadCpuTimesUs[cluster][speed].addCountLocked(
+                        systemServiceCpuThreadTimes.threadCpuTimesUs[index]);
+                mBinderThreadCpuTimesUs[cluster][speed].addCountLocked(
+                        systemServiceCpuThreadTimes.binderThreadCpuTimesUs[index]);
+                index++;
+            }
+        }
+        if (DEBUG_BINDER_STATS) {
+            Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
+            long binderThreadTime = 0;
+            long totalThreadTime = 0;
+            int cpuIndex = 0;
+            for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+                StringBuilder sb = new StringBuilder();
+                sb.append("cpu").append(cpuIndex).append(": [");
+                int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+                for (int speed = 0; speed < numSpeeds; speed++) {
+                    if (speed != 0) {
+                        sb.append(", ");
+                    }
+                    long totalCount = mSystemServerThreadCpuTimesUs[cluster][speed].getCountLocked(
+                            0) / 1000;
+                    long binderCount = mBinderThreadCpuTimesUs[cluster][speed].getCountLocked(0)
+                            / 1000;
+                    sb.append(String.format("%d/%d(%.1f%%)",
+                            binderCount,
+                            totalCount,
+                            totalCount != 0 ? (double) binderCount * 100 / totalCount : 0));
+
+                    totalThreadTime += totalCount;
+                    binderThreadTime += binderCount;
+                    index++;
+                }
+                cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
+                Slog.d(TAG, sb.toString());
+            }
+            Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTime);
+            Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
+                    binderThreadTime,
+                    binderThreadTime != 0 ? (double) binderThreadTime * 100 / totalThreadTime : 0));
+        }
     }
 
     /**
@@ -12998,6 +13137,75 @@
         }
     }
 
+
+    @Override
+    public long getSystemServiceTimeAtCpuSpeed(int cluster, int step) {
+        // Estimates the time spent by the system server handling incoming binder requests.
+        //
+        // The data that we can get from the kernel is this:
+        //   - CPU duration for a (thread - cluster - CPU speed) combination
+        //   - CPU duration for a (UID - cluster - CPU speed) combination
+        //
+        // The configuration we have in the Power Profile is this:
+        //   - Average CPU power for a (cluster - CPU speed) combination.
+        //
+        // The model used by BatteryStats can be illustrated with this example:
+        //
+        // - Let's say the system server has 10 threads.
+        // - These 10 threads spent 1000 ms of CPU time in aggregate
+        // - Of the 10 threads 4 were execute exclusively incoming binder calls.
+        // - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
+        // - The real time spent by the system server UID doing all of this is, say, 200 ms.
+        //
+        // We will assume that power consumption is proportional to the time spent by the CPU
+        // across all threads.  This is a crude assumption, but we don't have more detailed data.
+        // Thus,
+        //   binderRealTime = realTime * aggregateBinderThreadTime / aggregateAllThreadTime
+        //
+        // In our example,
+        //   binderRealTime = 200 * 600 / 1000 = 120ms
+        //
+        // We can then multiply this estimated time by the average power to obtain an estimate
+        // of the total power consumed by incoming binder calls for the given cluster/speed
+        // combination.
+
+        if (mSystemServerThreadCpuTimesUs == null) {
+            return 0;
+        }
+
+        if (cluster < 0 || cluster >= mSystemServerThreadCpuTimesUs.length) {
+            return 0;
+        }
+
+        final LongSamplingCounter[] threadTimesForCluster = mSystemServerThreadCpuTimesUs[cluster];
+
+        if (step < 0 || step >= threadTimesForCluster.length) {
+            return 0;
+        }
+
+        Uid systemUid = mUidStats.get(Process.SYSTEM_UID);
+        if (systemUid == null) {
+            return 0;
+        }
+
+        final long uidTimeAtCpuSpeed = systemUid.getTimeAtCpuSpeed(cluster, step,
+                BatteryStats.STATS_SINCE_CHARGED);
+        if (uidTimeAtCpuSpeed == 0) {
+            return 0;
+        }
+
+        final long uidThreadTime =
+                threadTimesForCluster[step].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+
+        if (uidThreadTime == 0) {
+            return 0;
+        }
+
+        final long binderThreadTime = mBinderThreadCpuTimesUs[cluster][step].getCountLocked(
+                BatteryStats.STATS_SINCE_CHARGED);
+        return uidTimeAtCpuSpeed * binderThreadTime / uidThreadTime;
+    }
+
     /**
      * Retrieve the statistics object for a particular uid, creating if needed.
      */
@@ -13327,45 +13535,7 @@
             pw.print(uid.getUserCpuTimeUs(STATS_SINCE_CHARGED) / 1000); pw.print(" ");
             pw.println(uid.getSystemCpuTimeUs(STATS_SINCE_CHARGED) / 1000);
         }
-        pw.println("Per UID system service calls:");
-        BinderTransactionNameResolver nameResolver = new BinderTransactionNameResolver();
-        for (int i = 0; i < size; i++) {
-            int u = mUidStats.keyAt(i);
-            Uid uid = mUidStats.get(u);
-            long binderCallCount = uid.getBinderCallCount();
-            if (binderCallCount != 0) {
-                pw.print(" ");
-                pw.print(u);
-                pw.print(" system service calls: ");
-                pw.print(binderCallCount);
-                ArraySet<BinderCallStats> binderCallStats = uid.getBinderCallStats();
-                if (!binderCallStats.isEmpty()) {
-                    pw.println(", including");
-                    BinderCallStats[] bcss = new BinderCallStats[binderCallStats.size()];
-                    binderCallStats.toArray(bcss);
-                    for (BinderCallStats bcs : bcss) {
-                        bcs.ensureMethodName(nameResolver);
-                    }
-                    Arrays.sort(bcss, BinderCallStats.COMPARATOR);
-                    for (BinderCallStats callStats : bcss) {
-                        pw.print("    ");
-                        pw.print(callStats.getClassName());
-                        pw.print('#');
-                        pw.print(callStats.getMethodName());
-                        pw.print(" calls: ");
-                        pw.print(callStats.callCount);
-                        if (callStats.recordedCallCount != 0) {
-                            pw.print(" time: ");
-                            pw.print(callStats.callCount * callStats.recordedCpuTimeMicros
-                                    / callStats.recordedCallCount / 1000);
-                        }
-                        pw.println();
-                    }
-                } else {
-                    pw.println();
-                }
-            }
-        }
+
         pw.println("Per UID CPU active time in ms:");
         for (int i = 0; i < size; i++) {
             int u = mUidStats.keyAt(i);
@@ -13390,6 +13560,30 @@
                 pw.print("  "); pw.print(u); pw.print(": "); pw.println(Arrays.toString(times));
             }
         }
+
+        updateSystemServiceCallStats();
+        if (mSystemServerThreadCpuTimesUs != null) {
+            pw.println("Per UID System server binder time in ms:");
+            for (int i = 0; i < size; i++) {
+                int u = mUidStats.keyAt(i);
+                Uid uid = mUidStats.get(u);
+                double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
+
+                long time = 0;
+                for (int cluster = 0; cluster < mSystemServerThreadCpuTimesUs.length; cluster++) {
+                    int numSpeeds = mSystemServerThreadCpuTimesUs[cluster].length;
+                    for (int speed = 0; speed < numSpeeds; speed++) {
+                        time += getSystemServiceTimeAtCpuSpeed(cluster, speed)
+                                * proportionalSystemServiceUsage;
+                    }
+                }
+
+                pw.print("  ");
+                pw.print(u);
+                pw.print(": ");
+                pw.println(time);
+            }
+        }
     }
 
     final ReentrantLock mWriteLock = new ReentrantLock();
@@ -14908,6 +15102,9 @@
             u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
             mUidStats.append(uid, u);
         }
+
+        mSystemServerThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
+        mBinderThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -14923,6 +15120,8 @@
         // Need to update with current kernel wake lock counts.
         pullPendingStateUpdatesLocked();
 
+        updateSystemServiceCallStats();
+
         // Pull the clock time.  This may update the time and make a new history entry
         // if we had originally pulled a time before the RTC was set.
         getStartClockTime();
@@ -15105,6 +15304,73 @@
         } else {
             out.writeInt(0);
         }
+        writeCpuSpeedCountersToParcel(out, mSystemServerThreadCpuTimesUs);
+        writeCpuSpeedCountersToParcel(out, mBinderThreadCpuTimesUs);
+    }
+
+    private void writeCpuSpeedCountersToParcel(Parcel out, LongSamplingCounter[][] counters) {
+        if (counters == null) {
+            out.writeInt(0);
+            return;
+        }
+
+        out.writeInt(1);
+        out.writeInt(counters.length);
+        for (int i = 0; i < counters.length; i++) {
+            LongSamplingCounter[] counterArray = counters[i];
+            if (counterArray == null) {
+                out.writeInt(0);
+                continue;
+            }
+
+            out.writeInt(1);
+            out.writeInt(counterArray.length);
+            for (int j = 0; j < counterArray.length; j++) {
+                LongSamplingCounter c = counterArray[j];
+                if (c != null) {
+                    out.writeInt(1);
+                    c.writeToParcel(out);
+                } else {
+                    out.writeInt(0);
+                }
+            }
+        }
+    }
+
+    private LongSamplingCounter[][] readCpuSpeedCountersFromParcel(Parcel in) {
+        LongSamplingCounter[][] counters;
+        if (in.readInt() != 0) {
+            int numCpuClusters = in.readInt();
+            if (mPowerProfile != null
+                    && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+                throw new ParcelFormatException("Incompatible number of cpu clusters");
+            }
+
+            counters = new LongSamplingCounter[numCpuClusters][];
+            for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+                if (in.readInt() != 0) {
+                    int numSpeeds = in.readInt();
+                    if (mPowerProfile != null
+                            && mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+                        throw new ParcelFormatException("Incompatible number of cpu speeds");
+                    }
+
+                    final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
+                    counters[cluster] = cpuSpeeds;
+                    for (int speed = 0; speed < numSpeeds; speed++) {
+                        if (in.readInt() != 0) {
+                            cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                        }
+                    }
+                } else {
+                    counters[cluster] = null;
+                }
+            }
+        } else {
+            counters = null;
+        }
+
+        return counters;
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index e09ef49..201626a 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -115,7 +115,8 @@
                     if (uidEntry != null) {
                         ArrayMap<CallStatKey, CallStat> callStats = uidEntry.mCallStats;
                         mCallStatsObserver.noteCallStats(uidEntry.workSourceUid,
-                                uidEntry.incrementalCallCount, callStats.values());
+                                uidEntry.incrementalCallCount, callStats.values(),
+                                mNativeTids.toArray());
                         uidEntry.incrementalCallCount = 0;
                         for (int j = callStats.size() - 1; j >= 0; j--) {
                             callStats.valueAt(j).incrementalCallCount = 0;
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index feb5aab..f14d5f2 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -142,7 +142,8 @@
          * Notes incoming binder call stats associated with this work source UID.
          */
         void noteCallStats(int workSourceUid, long incrementalCallCount,
-                Collection<BinderCallsStats.CallStat> callStats);
+                Collection<BinderCallsStats.CallStat> callStats,
+                int[] binderThreadNativeTids);
     }
 
     /**
diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java
index 1f816c1..749ff84 100644
--- a/core/java/com/android/internal/os/ChildZygoteInit.java
+++ b/core/java/com/android/internal/os/ChildZygoteInit.java
@@ -116,7 +116,7 @@
         try {
             server.registerServerSocketAtAbstractName(socketName);
 
-            // Add the abstract socket to the FD whitelist so that the native zygote code
+            // Add the abstract socket to the FD allow list so that the native zygote code
             // can properly detach it after forking.
             Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
 
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 3407670..2ba372a 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -225,19 +225,22 @@
 
     /** Set the number of frequency buckets to use */
     void setNumBuckets(int numBuckets) {
-        if (numBuckets < 1) {
-            Slog.w(TAG, "Number of buckets must be at least 1, but was " + numBuckets);
-            return;
-        }
         // If `numBuckets` hasn't changed since the last set, do nothing
         if (mFrequenciesKhz != null && mFrequenciesKhz.length == numBuckets) {
             return;
         }
-        mFrequencyBucketCreator =
-                new FrequencyBucketCreator(mProcTimeInStateReader.getFrequenciesKhz(), numBuckets);
-        mFrequenciesKhz =
-                mFrequencyBucketCreator.bucketFrequencies(
-                        mProcTimeInStateReader.getFrequenciesKhz());
+
+        final long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz();
+        if (numBuckets != 0) {
+            mFrequencyBucketCreator = new FrequencyBucketCreator(frequenciesKhz, numBuckets);
+            mFrequenciesKhz = mFrequencyBucketCreator.bucketFrequencies(frequenciesKhz);
+        } else {
+            mFrequencyBucketCreator = null;
+            mFrequenciesKhz = new int[frequenciesKhz.length];
+            for (int i = 0; i < frequenciesKhz.length; i++) {
+                mFrequenciesKhz[i] = (int) frequenciesKhz[i];
+            }
+        }
     }
 
     /** Set the UID predicate for {@link #getProcessCpuUsage} */
@@ -320,8 +323,15 @@
         if (cpuUsagesLong == null) {
             return null;
         }
-        int[] cpuUsages = mFrequencyBucketCreator.bucketValues(cpuUsagesLong);
-
+        final int[] cpuUsages;
+        if (mFrequencyBucketCreator != null) {
+            cpuUsages = mFrequencyBucketCreator.bucketValues(cpuUsagesLong);
+        } else {
+            cpuUsages = new int[cpuUsagesLong.length];
+            for (int i = 0; i < cpuUsagesLong.length; i++) {
+                cpuUsages[i] = (int) cpuUsagesLong[i];
+            }
+        }
         return new ThreadCpuUsage(threadId, threadName, cpuUsages);
     }
 
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 9283105..afc9432 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1 +1 @@
-per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
+per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
new file mode 100644
index 0000000..1cdd42c
--- /dev/null
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.Process;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
+ * by various threads of the System Server.
+ */
+public class SystemServerCpuThreadReader {
+    private KernelCpuThreadReader mKernelCpuThreadReader;
+    private int[] mBinderThreadNativeTids;
+
+    private int[] mThreadCpuTimesUs;
+    private int[] mBinderThreadCpuTimesUs;
+    private long[] mLastThreadCpuTimesUs;
+    private long[] mLastBinderThreadCpuTimesUs;
+
+    /**
+     * Times (in microseconds) spent by the system server UID.
+     */
+    public static class SystemServiceCpuThreadTimes {
+        // All threads
+        public long[] threadCpuTimesUs;
+        // Just the threads handling incoming binder calls
+        public long[] binderThreadCpuTimesUs;
+    }
+
+    private SystemServiceCpuThreadTimes mDeltaCpuThreadTimes = new SystemServiceCpuThreadTimes();
+
+    /**
+     * Creates a configured instance of SystemServerCpuThreadReader.
+     */
+    public static SystemServerCpuThreadReader create() {
+        return new SystemServerCpuThreadReader(
+                KernelCpuThreadReader.create(0, uid -> uid == Process.myUid()));
+    }
+
+    @VisibleForTesting
+    public SystemServerCpuThreadReader(Path procPath, int systemServerUid) throws IOException {
+        this(new KernelCpuThreadReader(0, uid -> uid == systemServerUid, null, null,
+                new KernelCpuThreadReader.Injector() {
+                    @Override
+                    public int getUidForPid(int pid) {
+                        return systemServerUid;
+                    }
+                }));
+    }
+
+    @VisibleForTesting
+    public SystemServerCpuThreadReader(KernelCpuThreadReader kernelCpuThreadReader) {
+        mKernelCpuThreadReader = kernelCpuThreadReader;
+    }
+
+    public void setBinderThreadNativeTids(int[] nativeTids) {
+        mBinderThreadNativeTids = nativeTids;
+    }
+
+    /**
+     * Returns delta of CPU times, per thread, since the previous call to this method.
+     */
+    public SystemServiceCpuThreadTimes readDelta() {
+        if (mBinderThreadCpuTimesUs == null) {
+            int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz().length;
+            mThreadCpuTimesUs = new int[numCpuFrequencies];
+            mBinderThreadCpuTimesUs = new int[numCpuFrequencies];
+
+            mLastThreadCpuTimesUs = new long[numCpuFrequencies];
+            mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
+
+            mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
+            mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
+        }
+
+        Arrays.fill(mThreadCpuTimesUs, 0);
+        Arrays.fill(mBinderThreadCpuTimesUs, 0);
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsage =
+                mKernelCpuThreadReader.getProcessCpuUsage();
+        int processCpuUsageSize = processCpuUsage.size();
+        for (int i = 0; i < processCpuUsageSize; i++) {
+            KernelCpuThreadReader.ProcessCpuUsage pcu = processCpuUsage.get(i);
+            ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages = pcu.threadCpuUsages;
+            if (threadCpuUsages != null) {
+                int threadCpuUsagesSize = threadCpuUsages.size();
+                for (int j = 0; j < threadCpuUsagesSize; j++) {
+                    KernelCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(j);
+                    boolean isBinderThread = isBinderThread(tcu.threadId);
+
+                    final int len = Math.min(tcu.usageTimesMillis.length, mThreadCpuTimesUs.length);
+                    for (int k = 0; k < len; k++) {
+                        int usageTimeUs = tcu.usageTimesMillis[k] * 1000;
+                        mThreadCpuTimesUs[k] += usageTimeUs;
+                        if (isBinderThread) {
+                            mBinderThreadCpuTimesUs[k] += usageTimeUs;
+                        }
+                    }
+                }
+            }
+        }
+
+        for (int i = 0; i < mThreadCpuTimesUs.length; i++) {
+            if (mThreadCpuTimesUs[i] < mLastThreadCpuTimesUs[i]) {
+                mDeltaCpuThreadTimes.threadCpuTimesUs[i] = mThreadCpuTimesUs[i];
+                mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
+            } else {
+                mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
+                        mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i];
+                mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
+                        mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i];
+            }
+            mLastThreadCpuTimesUs[i] = mThreadCpuTimesUs[i];
+            mLastBinderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
+        }
+
+        return mDeltaCpuThreadTimes;
+    }
+
+    private boolean isBinderThread(int threadId) {
+        if (mBinderThreadNativeTids != null) {
+            for (int i = 0; i < mBinderThreadNativeTids.length; i++) {
+                if (threadId == mBinderThreadNativeTids[i]) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
new file mode 100644
index 0000000..481b901
--- /dev/null
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.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 com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * Estimates the amount of power consumed by the System Server handling requests from
+ * a given app.
+ */
+public class SystemServicePowerCalculator extends PowerCalculator {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "SystemServicePowerCalc";
+
+    private static final long MICROSEC_IN_HR = (long) 60 * 60 * 1000 * 1000;
+
+    private final PowerProfile mPowerProfile;
+    private final BatteryStats mBatteryStats;
+    // Tracks system server CPU [cluster][speed] power in milliAmp-microseconds
+    private double[][] mSystemServicePowerMaUs;
+
+    public SystemServicePowerCalculator(PowerProfile powerProfile, BatteryStats batteryStats) {
+        mPowerProfile = powerProfile;
+        mBatteryStats = batteryStats;
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+            long rawUptimeUs, int statsType) {
+        final double proportionalUsage = u.getProportionalSystemServiceUsage();
+        if (proportionalUsage > 0) {
+            if (mSystemServicePowerMaUs == null) {
+                updateSystemServicePower();
+            }
+
+            double cpuPowerMaUs = 0;
+            int numCpuClusters = mPowerProfile.getNumCpuClusters();
+            for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+                final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+                for (int speed = 0; speed < numSpeeds; speed++) {
+                    cpuPowerMaUs += mSystemServicePowerMaUs[cluster][speed] * proportionalUsage;
+                }
+            }
+
+            app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
+        }
+    }
+
+    private void updateSystemServicePower() {
+        final int numCpuClusters = mPowerProfile.getNumCpuClusters();
+        mSystemServicePowerMaUs = new double[numCpuClusters][];
+        for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+            final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+            mSystemServicePowerMaUs[cluster] = new double[numSpeeds];
+            for (int speed = 0; speed < numSpeeds; speed++) {
+                mSystemServicePowerMaUs[cluster][speed] =
+                        mBatteryStats.getSystemServiceTimeAtCpuSpeed(cluster, speed)
+                                * mPowerProfile.getAveragePowerForCpuCore(cluster, speed);
+            }
+        }
+        if (DEBUG) {
+            Log.d(TAG, "System service power per CPU cluster and frequency");
+            for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+                Log.d(TAG, "Cluster[" + cluster  + "]: "
+                        + Arrays.toString(mSystemServicePowerMaUs[cluster]));
+            }
+        }
+    }
+
+    @Override
+    public void reset() {
+        mSystemServicePowerMaUs = null;
+    }
+}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 2989a5e..1ca9250 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -816,9 +816,9 @@
             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-app");
         } else if (args.mStartChildZygote) {
             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote");
-        } else if (args.mApiBlacklistExemptions != null) {
+        } else if (args.mApiDenylistExemptions != null) {
             throw new IllegalArgumentException(
-                USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions");
+                    USAP_ERROR_PREFIX + "--set-api-denylist-exemptions");
         } else if (args.mHiddenApiAccessLogSampleRate != -1) {
             throw new IllegalArgumentException(
                     USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 94c1f71..22082d0 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -192,10 +192,10 @@
     boolean mBootCompleted;
 
     /**
-     * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, or
-     * when they change, via --set-api-blacklist-exemptions.
+     * Exemptions from API deny-listing. These are sent to the pre-forked zygote at boot time, or
+     * when they change, via --set-api-denylist-exemptions.
      */
-    String[] mApiBlacklistExemptions;
+    String[] mApiDenylistExemptions;
 
     /**
      * Sampling rate for logging hidden API accesses to the event log. This is sent to the
@@ -416,10 +416,10 @@
                 expectRuntimeArgs = false;
             } else if (arg.equals("--start-child-zygote")) {
                 mStartChildZygote = true;
-            } else if (arg.equals("--set-api-blacklist-exemptions")) {
+            } else if (arg.equals("--set-api-denylist-exemptions")) {
                 // consume all remaining args; this is a stand-alone command, never included
                 // with the regular fork command.
-                mApiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
+                mApiDenylistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
                 curArg = args.length;
                 expectRuntimeArgs = false;
             } else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index ec1b05a..5a576ebb 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -185,8 +185,8 @@
             return null;
         }
 
-        if (parsedArgs.mApiBlacklistExemptions != null) {
-            return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
+        if (parsedArgs.mApiDenylistExemptions != null) {
+            return handleApiDenylistExemptions(zygoteServer, parsedArgs.mApiDenylistExemptions);
         }
 
         if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
@@ -367,11 +367,11 @@
     }
 
     /**
-     * Makes the necessary changes to implement a new API blacklist exemption policy, and then
+     * Makes the necessary changes to implement a new API deny list exemption policy, and then
      * responds to the system server, letting it know that the task has been completed.
      *
      * This necessitates a change to the internal state of the Zygote.  As such, if the USAP
-     * pool is enabled all existing USAPs have an incorrect API blacklist exemption list.  To
+     * pool is enabled all existing USAPs have an incorrect API deny list exemption list.  To
      * properly handle this request the pool must be emptied and refilled.  This process can return
      * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
      *
@@ -380,9 +380,9 @@
      * @return A Runnable object representing a new app in any USAPs spawned from here; the
      *         zygote process will always receive a null value from this function.
      */
-    private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
+    private Runnable handleApiDenylistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
         return stateChangeWithUsapPoolReset(zygoteServer,
-                () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
+                () -> ZygoteInit.setApiDenylistExemptions(exemptions));
     }
 
     private Runnable handleUsapPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5fd9333..32e7fdc 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -583,7 +583,10 @@
         VMRuntime.registerAppInfo(profilePath, codePaths);
     }
 
-    public static void setApiBlacklistExemptions(String[] exemptions) {
+    /**
+     * Sets the list of classes/methods for the hidden API
+     */
+    public static void setApiDenylistExemptions(String[] exemptions) {
         VMRuntime.getRuntime().setHiddenApiExemptions(exemptions);
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index a0b50df..bb17337 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -451,7 +451,7 @@
              * For reasons of correctness the USAP pool pipe and event FDs
              * must be processed before the session and server sockets.  This
              * is to ensure that the USAP pool accounting information is
-             * accurate when handling other requests like API blacklist
+             * accurate when handling other requests like API deny list
              * exemptions.
              */
 
diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
index ba60fa5..b42ea7d 100644
--- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
+++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
@@ -16,14 +16,8 @@
 
 package com.android.internal.os.logging;
 
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.util.Pair;
 import android.view.WindowManager.LayoutParams;
 
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.FrameworkStatsLog;
 
 /**
@@ -32,81 +26,6 @@
  */
 public class MetricsLoggerWrapper {
 
-    private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0;
-    private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1;
-
-    public static void logPictureInPictureDismissByTap(Context context,
-            Pair<ComponentName, Integer> topActivityInfo) {
-        MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
-                METRIC_VALUE_DISMISSED_BY_TAP);
-        FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
-                getUid(context, topActivityInfo.first, topActivityInfo.second),
-                topActivityInfo.first.flattenToString(),
-                FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED);
-    }
-
-    public static void logPictureInPictureDismissByDrag(Context context,
-            Pair<ComponentName, Integer> topActivityInfo) {
-        MetricsLogger.action(context,
-                MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
-                METRIC_VALUE_DISMISSED_BY_DRAG);
-        FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
-                getUid(context, topActivityInfo.first, topActivityInfo.second),
-                topActivityInfo.first.flattenToString(),
-                FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED);
-    }
-
-    public static void logPictureInPictureMinimize(Context context, boolean isMinimized,
-            Pair<ComponentName, Integer> topActivityInfo) {
-        MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED,
-                isMinimized);
-        FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
-                getUid(context, topActivityInfo.first, topActivityInfo.second),
-                topActivityInfo.first.flattenToString(),
-                FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__MINIMIZED);
-    }
-
-    /**
-     * Get uid from component name and user Id
-     * @return uid. -1 if not found.
-     */
-    private static int getUid(Context context, ComponentName componentName, int userId) {
-        int uid = -1;
-        if (componentName == null) {
-            return uid;
-        }
-        try {
-            uid = context.getPackageManager().getApplicationInfoAsUser(
-                    componentName.getPackageName(), 0, userId).uid;
-        } catch (NameNotFoundException e) {
-        }
-        return uid;
-    }
-
-    public static void logPictureInPictureMenuVisible(Context context, boolean menuStateFull) {
-        MetricsLogger.visibility(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
-                menuStateFull);
-    }
-
-    public static void logPictureInPictureEnter(Context context,
-            int uid, String shortComponentName, boolean supportsEnterPipOnTaskSwitch) {
-        MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_ENTERED,
-                supportsEnterPipOnTaskSwitch);
-        FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, uid,
-                shortComponentName,
-                FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__ENTERED);
-    }
-
-    public static void logPictureInPictureFullScreen(Context context, int uid,
-            String shortComponentName) {
-        MetricsLogger.action(context,
-                MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN);
-        FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
-                uid,
-                shortComponentName,
-                FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN);
-    }
-
     public static void logAppOverlayEnter(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) {
         if (changed) {
             if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) {
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index 0e703fa..205c5fd 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -103,8 +103,11 @@
         final DisplayMetrics dm = userRes.getDisplayMetrics();
         final float defaultInset = userRes.getDimension(
                 com.android.internal.R.dimen.config_backGestureInset) / dm.density;
-        final float backGestureInset = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
-                BACK_GESTURE_EDGE_WIDTH, defaultInset);
+        // Only apply the back gesture config if there is an existing inset
+        final float backGestureInset = defaultInset > 0
+                ? DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
+                        BACK_GESTURE_EDGE_WIDTH, defaultInset)
+                : defaultInset;
         final float inset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, backGestureInset,
                 dm);
         final float scale = Settings.Secure.getFloatForUser(
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 0a3fe09..053b06f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -35,6 +35,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiContext;
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.SearchManager;
@@ -342,7 +343,7 @@
     static final RotationWatcher sRotationWatcher = new RotationWatcher();
 
     @UnsupportedAppUsage
-    public PhoneWindow(Context context) {
+    public PhoneWindow(@UiContext Context context) {
         super(context);
         mLayoutInflater = LayoutInflater.from(context);
         mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
@@ -352,7 +353,7 @@
     /**
      * Constructor for main window of an activity.
      */
-    public PhoneWindow(Context context, Window preservedWindow,
+    public PhoneWindow(@UiContext Context context, Window preservedWindow,
             ActivityConfigCallback activityConfigCallback) {
         this(context);
         // Only main activity windows use decor context, all the other windows depend on whatever
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 5a04992..ea09fc8 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -65,9 +65,7 @@
     void notifyDataActivity(int state);
     void notifyDataActivityForSubscriber(in int subId, int state);
     void notifyDataConnectionForSubscriber(
-            int phoneId, int subId, int apnType, in PreciseDataConnectionState preciseState);
-    @UnsupportedAppUsage
-    void notifyDataConnectionFailed(String apnType);
+            int phoneId, int subId, in PreciseDataConnectionState preciseState);
     // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
     void notifyCellLocation(in CellIdentity cellLocation);
     void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
@@ -77,8 +75,6 @@
             int foregroundCallState, int backgroundCallState);
     void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
             int preciseDisconnectCause);
-    void notifyPreciseDataConnectionFailed(int phoneId, int subId, int apnType, String apn,
-            int failCause);
     void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
     void notifySrvccStateChanged(in int subId, in int lteState);
     void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index c6a1153..6b754ca 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -19,6 +19,7 @@
 import static com.android.internal.util.ArrayUtils.appendInt;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.pm.FeatureInfo;
@@ -245,6 +246,14 @@
      */
     private Map<String, Map<String, String>> mNamedActors = null;
 
+    // Package name of the package pre-installed on a read-only
+    // partition that is used to verify if an overlay package fulfills
+    // the 'config_signature' policy by comparing their signatures:
+    // if the overlay package is signed with the same certificate as
+    // the package declared in 'config-signature' tag, then the
+    // overlay package fulfills the 'config_signature' policy.
+    private String mOverlayConfigSignaturePackage;
+
     public static SystemConfig getInstance() {
         if (!isSystemProcess()) {
             Slog.wtf(TAG, "SystemConfig is being accessed by a process other than "
@@ -432,6 +441,12 @@
         return mNamedActors != null ? mNamedActors : Collections.emptyMap();
     }
 
+    @Nullable
+    public String getOverlayConfigSignaturePackage() {
+        return TextUtils.isEmpty(mOverlayConfigSignaturePackage)
+                ? null : mOverlayConfigSignaturePackage;
+    }
+
     /**
      * Only use for testing. Do NOT use in production code.
      * @param readPermissions false to create an empty SystemConfig; true to read the permissions.
@@ -1137,6 +1152,27 @@
                         }
                         XmlUtils.skipCurrentTag(parser);
                     } break;
+                    case "overlay-config-signature": {
+                        if (allowAll) {
+                            String pkgName = parser.getAttributeValue(null, "package");
+                            if (pkgName == null) {
+                                Slog.w(TAG, "<" + name + "> without package in " + permFile
+                                        + " at " + parser.getPositionDescription());
+                            } else {
+                                if (TextUtils.isEmpty(mOverlayConfigSignaturePackage)) {
+                                    mOverlayConfigSignaturePackage = pkgName.intern();
+                                } else {
+                                    throw new IllegalStateException("Reference signature package "
+                                                  + "defined as both "
+                                                  + mOverlayConfigSignaturePackage
+                                                  + " and " + pkgName);
+                                }
+                            }
+                        } else {
+                            logNotAllowedInPartition(name, permFile, parser);
+                        }
+                        XmlUtils.skipCurrentTag(parser);
+                    } break;
                     case "rollback-whitelisted-app": {
                         String pkgname = parser.getAttributeValue(null, "package");
                         if (pkgname == null) {
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index d7d8621..7d80993 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -17,4 +17,4 @@
 per-file android_view_PointerIcon.* = michaelwr@google.com, svv@google.com
 
 # Zygote
-per-file com_android_internal_os_Zygote.*,fd_utils.* = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
+per-file com_android_internal_os_Zygote.*,fd_utils.* = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index ff73c74..7756a62 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -30,7 +30,7 @@
 static struct {
     jfieldID ptr;
     jfieldID name;
-    jfieldID dispatchingTimeoutNanos;
+    jfieldID dispatchingTimeoutMillis;
     jfieldID token;
 } gInputApplicationHandleClassInfo;
 
@@ -61,8 +61,8 @@
 
     mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
 
-    mInfo.dispatchingTimeoutNanos =
-            env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+    mInfo.dispatchingTimeoutMillis =
+            env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
 
     jobject tokenObj = env->GetObjectField(obj,
             gInputApplicationHandleClassInfo.token);
@@ -144,9 +144,8 @@
     GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz,
             "name", "Ljava/lang/String;");
 
-    GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos,
-            clazz,
-            "dispatchingTimeoutNanos", "J");
+    GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutMillis, clazz,
+                 "dispatchingTimeoutMillis", "J");
 
     GET_FIELD_ID(gInputApplicationHandleClassInfo.token, clazz,
             "token", "Landroid/os/IBinder;");
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 796c5c4..ecdba3f 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -47,7 +47,7 @@
     jfieldID name;
     jfieldID layoutParamsFlags;
     jfieldID layoutParamsType;
-    jfieldID dispatchingTimeoutNanos;
+    jfieldID dispatchingTimeoutMillis;
     jfieldID frameLeft;
     jfieldID frameTop;
     jfieldID frameRight;
@@ -118,8 +118,8 @@
             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
     mInfo.type = static_cast<InputWindowInfo::Type>(
             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
-    mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
-            env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutNanos));
+    mInfo.dispatchingTimeout = std::chrono::milliseconds(
+            env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
     mInfo.frameLeft = env->GetIntField(obj,
             gInputWindowHandleClassInfo.frameLeft);
     mInfo.frameTop = env->GetIntField(obj,
@@ -293,8 +293,8 @@
     GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
             "layoutParamsType", "I");
 
-    GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
-            "dispatchingTimeoutNanos", "J");
+    GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutMillis, clazz,
+                 "dispatchingTimeoutMillis", "J");
 
     GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
             "frameLeft", "I");
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 22bb210..1f62544 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -974,7 +974,7 @@
         if (jHandle == NULL) {
             return (jint)AUDIO_JAVA_ERROR;
         }
-        // create dummy port and port config objects with just the correct handle
+        // create placeholder port and port config objects with just the correct handle
         // and configuration data. The actual AudioPortConfig objects will be
         // constructed by java code with correct class type (device, mix etc...)
         // and reference to AudioPort instance in this client
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index e56809f..8d4c4e5 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -93,13 +93,13 @@
 
 static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
-    int dummy = 0;
+    int optval_ignored = 0;
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
-    if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)) != 0) {
+    if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &optval_ignored, sizeof(optval_ignored)) !=
+        0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
                 "setsockopt(SO_DETACH_FILTER): %s", strerror(errno));
     }
-
 }
 
 static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index d6e8531..ef0eeec 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -920,7 +920,7 @@
 {
     jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
 
-    // Sanity check the number of other statistics expected in Java matches here.
+    // Check the number of other statistics expected in Java matches here.
     jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
     jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
     jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I");
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 2000ecb..7cfe3bc 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -330,7 +330,7 @@
     if (parcel != NULL) {
         int32_t len = parcel->readInt32();
 
-        // sanity check the stored length against the true data size
+        // Validate the stored length against the true data size
         if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
             ret = env->NewByteArray(len);
 
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 885b0a3..e118038 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -962,7 +962,7 @@
 
 static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
 {
-    // XXX temporary sanity check to debug crashes.
+    // XXX temporary validation check to debug crashes.
     int uid = (int)(token>>32);
     if (uid > 0 && uid < 999) {
         // In Android currently there are no uids in this range.
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 7daefd3..e715be2 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -95,8 +95,8 @@
     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
     if (receiverObj.get()) {
         ALOGV("receiver %p ~ Invoking vsync handler.", this);
-        env->CallVoidMethod(receiverObj.get(),
-                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);
+        env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
+                            timestamp, displayId.value, count);
         ALOGV("receiver %p ~ Returned from vsync handler.", this);
     }
 
@@ -110,8 +110,8 @@
     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
     if (receiverObj.get()) {
         ALOGV("receiver %p ~ Invoking hotplug handler.", this);
-        env->CallVoidMethod(receiverObj.get(),
-                gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, displayId, connected);
+        env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchHotplug,
+                            timestamp, displayId.value, connected);
         ALOGV("receiver %p ~ Returned from hotplug handler.", this);
     }
 
@@ -126,9 +126,8 @@
                                       jniGetReferent(env, mReceiverWeakGlobal));
   if (receiverObj.get()) {
     ALOGV("receiver %p ~ Invoking config changed handler.", this);
-    env->CallVoidMethod(receiverObj.get(),
-                        gDisplayEventReceiverClassInfo.dispatchConfigChanged,
-                        timestamp, displayId, configId);
+    env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchConfigChanged,
+                        timestamp, displayId.value, configId);
     ALOGV("receiver %p ~ Returned from config changed handler.", this);
   }
 
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 24c3ff8..70a9be7 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -176,8 +176,8 @@
     Mutex::Autolock _l(mLock);
     mPendingEvents.push(event);
     if (mPendingEvents.size() == 1) {
-        char dummy = 0;
-        int res = TEMP_FAILURE_RETRY(write(mDispatchWriteFd, &dummy, sizeof(dummy)));
+        char payload = '\0';
+        int res = TEMP_FAILURE_RETRY(write(mDispatchWriteFd, &payload, sizeof(payload)));
         if (res < 0 && errno != EAGAIN) {
             ALOGW("Failed writing to dispatch fd: %s", strerror(errno));
         }
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a965ab3..d6a773f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -104,6 +104,27 @@
     jfieldID top;
 } gRectClassInfo;
 
+static struct {
+    jfieldID pixelFormat;
+    jfieldID sourceCrop;
+    jfieldID frameScale;
+    jfieldID captureSecureLayers;
+} gCaptureArgsClassInfo;
+
+static struct {
+    jfieldID displayToken;
+    jfieldID width;
+    jfieldID height;
+    jfieldID useIdentityTransform;
+    jfieldID rotation;
+} gDisplayCaptureArgsClassInfo;
+
+static struct {
+    jfieldID layer;
+    jfieldID excludeLayers;
+    jfieldID childrenOnly;
+} gLayerCaptureArgsClassInfo;
+
 // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
 void DeleteScreenshot(void* addr, void* context) {
     delete ((ScreenshotClient*) context);
@@ -276,55 +297,79 @@
     return Rect(left, top, right, bottom);
 }
 
-static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
-        jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
-        bool useIdentityTransform, int rotation, bool captureSecureLayers) {
-    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
-    if (displayToken == NULL) {
+static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& captureArgs) {
+    captureArgs.pixelFormat = static_cast<ui::PixelFormat>(
+            env->GetIntField(captureArgsObject, gCaptureArgsClassInfo.pixelFormat));
+    captureArgs.sourceCrop =
+            rectFromObj(env,
+                        env->GetObjectField(captureArgsObject, gCaptureArgsClassInfo.sourceCrop));
+    captureArgs.frameScale =
+            env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScale);
+    captureArgs.captureSecureLayers =
+            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
+}
+
+static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
+                                                       jobject displayCaptureArgsObject) {
+    DisplayCaptureArgs captureArgs;
+    getCaptureArgs(env, displayCaptureArgsObject, captureArgs);
+
+    captureArgs.displayToken =
+            ibinderForJavaObject(env,
+                                 env->GetObjectField(displayCaptureArgsObject,
+                                                     gDisplayCaptureArgsClassInfo.displayToken));
+    captureArgs.width =
+            env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width);
+    captureArgs.height =
+            env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height);
+    captureArgs.useIdentityTransform =
+            env->GetBooleanField(displayCaptureArgsObject,
+                                 gDisplayCaptureArgsClassInfo.useIdentityTransform);
+    captureArgs.rotation = ui::toRotation(
+            env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.rotation));
+    return captureArgs;
+}
+
+static jobject nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject) {
+    const DisplayCaptureArgs captureArgs =
+            displayCaptureArgsFromObject(env, displayCaptureArgsObject);
+
+    if (captureArgs.displayToken == NULL) {
         return NULL;
     }
-    const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
-    const ui::Dataspace dataspace = pickDataspaceFromColorMode(colorMode);
 
-    Rect sourceCrop = rectFromObj(env, sourceCropObj);
-    sp<GraphicBuffer> buffer;
-    bool capturedSecureLayers = false;
-    status_t res = ScreenshotClient::capture(displayToken, dataspace,
-            ui::PixelFormat::RGBA_8888,
-            sourceCrop, width, height,
-            useIdentityTransform, ui::toRotation(rotation),
-            captureSecureLayers, &buffer, capturedSecureLayers);
+    ScreenCaptureResults captureResults;
+    status_t res = ScreenshotClient::captureDisplay(captureArgs, captureResults);
     if (res != NO_ERROR) {
         return NULL;
     }
 
-    jobject jhardwareBuffer =
-            android_hardware_HardwareBuffer_createFromAHardwareBuffer(env,
-                                                                      buffer->toAHardwareBuffer());
-    const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
+    jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+            env, captureResults.buffer->toAHardwareBuffer());
+    const jint namedColorSpace =
+            fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
     return env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
                                        gScreenshotHardwareBufferClassInfo.builder, jhardwareBuffer,
-                                       namedColorSpace, capturedSecureLayers);
+                                       namedColorSpace, captureResults.capturedSecureLayers);
 }
 
-static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj,
-        jlong layerObject, jobject sourceCropObj, jfloat frameScale,
-        jlongArray excludeObjectArray, jint format) {
-
-    auto layer = reinterpret_cast<SurfaceControl *>(layerObject);
-    if (layer == NULL) {
-        return NULL;
+static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject) {
+    LayerCaptureArgs captureArgs;
+    getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
+    SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
+            env->GetLongField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.layer));
+    if (layer == nullptr) {
+        return nullptr;
     }
 
-    Rect sourceCrop;
-    if (sourceCropObj != NULL) {
-        sourceCrop = rectFromObj(env, sourceCropObj);
-    }
-
-    std::unordered_set<sp<IBinder>,ISurfaceComposer::SpHash<IBinder>> excludeHandles;
+    captureArgs.layerHandle = layer->getHandle();
+    captureArgs.childrenOnly =
+            env->GetBooleanField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.childrenOnly);
+    jlongArray excludeObjectArray = reinterpret_cast<jlongArray>(
+            env->GetObjectField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.excludeLayers));
     if (excludeObjectArray != NULL) {
         const jsize len = env->GetArrayLength(excludeObjectArray);
-        excludeHandles.reserve(len);
+        captureArgs.excludeHandles.reserve(len);
 
         const jlong* objects = env->GetLongArrayElements(excludeObjectArray, nullptr);
         for (jsize i = 0; i < len; i++) {
@@ -333,33 +378,24 @@
                 jniThrowNullPointerException(env, "Exclude layer is null");
                 return NULL;
             }
-            excludeHandles.emplace(excludeObject->getHandle());
+            captureArgs.excludeHandles.emplace(excludeObject->getHandle());
         }
         env->ReleaseLongArrayElements(excludeObjectArray, const_cast<jlong*>(objects), JNI_ABORT);
     }
 
-    sp<GraphicBuffer> buffer;
-    ui::Dataspace dataspace = ui::Dataspace::V0_SRGB;
-    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
-    if (displayToken != nullptr) {
-        const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
-        dataspace = pickDataspaceFromColorMode(colorMode);
-    }
-    status_t res = ScreenshotClient::captureChildLayers(layer->getHandle(), dataspace,
-                                                        static_cast<ui::PixelFormat>(format),
-                                                        sourceCrop, excludeHandles, frameScale,
-                                                        &buffer);
+    ScreenCaptureResults captureResults;
+    status_t res = ScreenshotClient::captureLayers(captureArgs, captureResults);
     if (res != NO_ERROR) {
         return NULL;
     }
 
-    jobject jhardwareBuffer =
-            android_hardware_HardwareBuffer_createFromAHardwareBuffer(env,
-                                                                      buffer->toAHardwareBuffer());
-    const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
+    jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+            env, captureResults.buffer->toAHardwareBuffer());
+    const jint namedColorSpace =
+            fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
     return env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
                                        gScreenshotHardwareBufferClassInfo.builder, jhardwareBuffer,
-                                       namedColorSpace, false /* capturedSecureLayers */);
+                                       namedColorSpace, captureResults.capturedSecureLayers);
 }
 
 static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
@@ -667,7 +703,7 @@
 
     jlong* values = env->GetLongArrayElements(array, 0);
     for (size_t i = 0; i < displayIds.size(); ++i) {
-        values[i] = static_cast<jlong>(displayIds[i]);
+        values[i] = static_cast<jlong>(displayIds[i].value);
     }
 
     env->ReleaseLongArrayElements(array, values, 0);
@@ -675,7 +711,8 @@
 }
 
 static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
-    sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(physicalDisplayId);
+    sp<IBinder> token =
+            SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId));
     return javaObjectForIBinder(env, token);
 }
 
@@ -1614,13 +1651,12 @@
             (void*)nativeSeverChildren } ,
     {"nativeSetOverrideScalingMode", "(JJI)V",
             (void*)nativeSetOverrideScalingMode },
-    {"nativeScreenshot",
-            "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZIZ)"
+    {"nativeCaptureDisplay",
+            "(Landroid/view/SurfaceControl$DisplayCaptureArgs;)"
             "Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;",
-            (void*)nativeScreenshot },
+            (void*)nativeCaptureDisplay },
     {"nativeCaptureLayers",
-            "(Landroid/os/IBinder;JLandroid/graphics/Rect;"
-            "F[JI)"
+            "(Landroid/view/SurfaceControl$LayerCaptureArgs;)"
             "Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;",
             (void*)nativeCaptureLayers },
     {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
@@ -1795,6 +1831,36 @@
     gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
             GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");
 
+    jclass captureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$CaptureArgs");
+    gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
+    gCaptureArgsClassInfo.sourceCrop =
+            GetFieldIDOrDie(env, captureArgsClazz, "mSourceCrop", "Landroid/graphics/Rect;");
+    gCaptureArgsClassInfo.frameScale = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScale", "F");
+    gCaptureArgsClassInfo.captureSecureLayers =
+            GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
+
+    jclass displayCaptureArgsClazz =
+            FindClassOrDie(env, "android/view/SurfaceControl$DisplayCaptureArgs");
+    gDisplayCaptureArgsClassInfo.displayToken =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;");
+    gDisplayCaptureArgsClassInfo.width =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I");
+    gDisplayCaptureArgsClassInfo.height =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I");
+    gDisplayCaptureArgsClassInfo.useIdentityTransform =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z");
+    gDisplayCaptureArgsClassInfo.rotation =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mRotation", "I");
+
+    jclass layerCaptureArgsClazz =
+            FindClassOrDie(env, "android/view/SurfaceControl$LayerCaptureArgs");
+    gLayerCaptureArgsClassInfo.layer =
+            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeLayer", "J");
+    gLayerCaptureArgsClassInfo.excludeLayers =
+            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeExcludeLayers", "[J");
+    gLayerCaptureArgsClassInfo.childrenOnly =
+            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");
+
     return err;
 }
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index fe540bb..e4a142b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -449,7 +449,7 @@
         // Game Driver - List of Apps that are allowed to use Game Driver
         optional SettingProto game_driver_allowlist = 12;
         // ANGLE - List of Apps that can check ANGLE rules
-        optional SettingProto angle_whitelist = 13;
+        optional SettingProto angle_allowlist = 13;
         // Game Driver - List of denylists, each denylist is a denylist for
         // a specific Game Driver version
         optional SettingProto game_driver_denylists = 14;
diff --git a/core/proto/android/server/alarm/alarmmanagerservice.proto b/core/proto/android/server/alarm/alarmmanagerservice.proto
index b74991d..e1240245 100644
--- a/core/proto/android/server/alarm/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarm/alarmmanagerservice.proto
@@ -59,9 +59,10 @@
     // Time since the last wakeup was set.
     optional int64 time_since_last_wakeup_set_ms = 15;
     optional int64 time_change_event_count = 16;
-    // The current set of user whitelisted apps for device idle mode, meaning
+    // The current set of user exempted apps for device idle mode, meaning
     // these are allowed to freely schedule alarms. These are app IDs, not UIDs.
-    repeated int32 device_idle_user_whitelist_app_ids = 17;
+    // This field is currently unused.
+    repeated int32 device_idle_user_exempt_app_ids = 17;
 
     repeated AlarmClockMetadataProto next_alarm_clock_metadata = 18;
 
diff --git a/core/proto/android/server/appstatetracker.proto b/core/proto/android/server/appstatetracker.proto
index 51e8845..f5583d4 100644
--- a/core/proto/android/server/appstatetracker.proto
+++ b/core/proto/android/server/appstatetracker.proto
@@ -41,14 +41,14 @@
     // UIDs currently in the foreground.
     repeated int32 foreground_uids = 11;
 
-    // App ids that are in power-save whitelist.
-    repeated int32 power_save_whitelist_app_ids = 3;
+    // App ids that are in power-save exemption list.
+    repeated int32 power_save_exempt_app_ids = 3;
 
-    // App ids that are in power-save user whitelist.
-    repeated int32 power_save_user_whitelist_app_ids = 12;
+    // App ids that are in power-save user exemption list.
+    repeated int32 power_save_user_exempt_app_ids = 12;
 
-    // App ids that are in temporary power-save whitelist.
-    repeated int32 temp_power_save_whitelist_app_ids = 4;
+    // App ids that are in temporary power-save exemption list.
+    repeated int32 temp_power_save_exempt_app_ids = 4;
 
     message RunAnyInBackgroundRestrictedPackages {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -79,5 +79,5 @@
     }
 
     // Packages that are in the EXEMPT bucket.
-    repeated ExemptedPackage exempted_packages = 10;
+    repeated ExemptedPackage exempted_bucket_packages = 10;
 }
diff --git a/core/tests/coretests/apks/install/res/values/strings.xml b/core/tests/coretests/apks/install/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install/res/values/strings.xml
+++ b/core/tests/coretests/apks/install/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml b/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml b/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml b/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml b/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml b/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml b/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml b/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml b/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml b/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml b/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/keyset/res/values/strings.xml b/core/tests/coretests/apks/keyset/res/values/strings.xml
index ff99ffa..d811ec2 100644
--- a/core/tests/coretests/apks/keyset/res/values/strings.xml
+++ b/core/tests/coretests/apks/keyset/res/values/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
   <string name="keyset_perm_desc">keyset_perm_description</string>
   <string name="keyset_perm_label">keyset_perm_label</string>
 </resources>
diff --git a/core/tests/coretests/apks/version/res/values/strings.xml b/core/tests/coretests/apks/version/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/version/res/values/strings.xml
+++ b/core/tests/coretests/apks/version/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/apks/version_nosys/res/values/strings.xml b/core/tests/coretests/apks/version_nosys/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/version_nosys/res/values/strings.xml
+++ b/core/tests/coretests/apks/version_nosys/res/values/strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="dummy">dummy</string>
+  <string name="placeholder">placeholder</string>
 </resources>
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
index 3e67b8b..22c41f3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
@@ -38,7 +38,8 @@
 @SmallTest
 public class BatteryStatsBinderCallStatsTest extends TestCase {
 
-    private static final int TRANSACTION_CODE = 100;
+    private static final int TRANSACTION_CODE1 = 100;
+    private static final int TRANSACTION_CODE2 = 101;
 
     /**
      * Test BatteryStatsImpl.Uid.noteBinderCallStats.
@@ -53,23 +54,23 @@
 
         Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
         BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(callingUid,
-                MockBinder.class, TRANSACTION_CODE, true /*screenInteractive */);
+                MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
         stat1.incrementalCallCount = 21;
         stat1.recordedCallCount = 5;
         stat1.cpuTimeMicros = 1000;
         callStats.add(stat1);
 
-        bi.noteBinderCallStats(workSourceUid, 42, callStats);
+        bi.noteBinderCallStats(workSourceUid, 42, callStats, null);
 
         callStats.clear();
         BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(callingUid,
-                MockBinder.class, TRANSACTION_CODE, true /*screenInteractive */);
+                MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
         stat2.incrementalCallCount = 9;
         stat2.recordedCallCount = 8;
         stat2.cpuTimeMicros = 500;
         callStats.add(stat2);
 
-        bi.noteBinderCallStats(workSourceUid, 8, callStats);
+        bi.noteBinderCallStats(workSourceUid, 8, callStats, null);
 
         BatteryStatsImpl.Uid uid = bi.getUidStatsLocked(workSourceUid);
         assertEquals(42 + 8, uid.getBinderCallCount());
@@ -85,9 +86,62 @@
         assertEquals(500, value.recordedCpuTimeMicros);
     }
 
+
+    @Test
+    public void testProportionalSystemServiceUsage_noStatsForSomeMethods() throws Exception {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+        int callingUid = Process.FIRST_APPLICATION_UID + 1;
+        int workSourceUid1 = Process.FIRST_APPLICATION_UID + 1;
+        int workSourceUid2 = Process.FIRST_APPLICATION_UID + 2;
+        int workSourceUid3 = Process.FIRST_APPLICATION_UID + 3;
+
+        Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+        BinderCallsStats.CallStat stat1a = new BinderCallsStats.CallStat(callingUid,
+                MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
+        stat1a.incrementalCallCount = 10;
+        stat1a.recordedCallCount = 5;
+        stat1a.cpuTimeMicros = 1000;
+        callStats.add(stat1a);
+
+        BinderCallsStats.CallStat stat1b = new BinderCallsStats.CallStat(callingUid,
+                MockBinder.class, TRANSACTION_CODE2, true /*screenInteractive */);
+        stat1b.incrementalCallCount = 30;
+        stat1b.recordedCallCount = 15;
+        stat1b.cpuTimeMicros = 1500;
+        callStats.add(stat1b);
+
+        bi.noteBinderCallStats(workSourceUid1, 65, callStats, null);
+
+        // No recorded stats for some methods. Must use the global average.
+        callStats.clear();
+        BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(callingUid,
+                MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
+        stat2.incrementalCallCount = 10;
+        callStats.add(stat2);
+
+        bi.noteBinderCallStats(workSourceUid2, 40, callStats, null);
+
+        // No stats for any calls. Must use the global average
+        callStats.clear();
+        bi.noteBinderCallStats(workSourceUid3, 50, callStats, null);
+
+        bi.updateSystemServiceCallStats();
+
+        double prop1 = bi.getUidStatsLocked(workSourceUid1).getProportionalSystemServiceUsage();
+        double prop2 = bi.getUidStatsLocked(workSourceUid2).getProportionalSystemServiceUsage();
+        double prop3 = bi.getUidStatsLocked(workSourceUid3).getProportionalSystemServiceUsage();
+
+        assertEquals(0.419, prop1, 0.01);
+        assertEquals(0.258, prop2, 0.01);
+        assertEquals(0.323, prop3, 0.01);
+        assertEquals(1.000, prop1 + prop2 + prop3, 0.01);
+    }
+
     private static class MockBinder extends Binder {
         public static String getDefaultTransactionName(int txCode) {
-            return txCode == TRANSACTION_CODE ? "testMethod" : "unknown";
+            return txCode == TRANSACTION_CODE1 ? "testMethod" : "unknown";
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index a5117a3..188ba9e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -768,8 +768,8 @@
 
         final ArrayList<BinderCallsStats.CallStat> callStatsList = new ArrayList<>();
         bcs.setCallStatsObserver(
-                (workSourceUid, incrementalCallCount, callStats) -> callStatsList.addAll(
-                        callStats));
+                (workSourceUid, incrementalCallCount, callStats, binderThreadIds) ->
+                        callStatsList.addAll(callStats));
 
         Binder binder = new Binder();
 
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 bc0e0a4..75dd7fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -133,6 +133,12 @@
         return this;
     }
 
+    public MockBatteryStatsImpl setSystemServerCpuThreadReader(
+            SystemServerCpuThreadReader systemServerCpuThreadReader) {
+        mSystemServerCpuThreadReader = systemServerCpuThreadReader;
+        return this;
+    }
+
     public MockBatteryStatsImpl setUserInfoProvider(UserInfoProvider provider) {
         mUserInfoProvider = provider;
         return this;
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
new file mode 100644
index 0000000..10ba548
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemServerCpuThreadReaderTest {
+    private File mProcDirectory;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getContext();
+        mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        FileUtils.deleteContents(mProcDirectory);
+    }
+
+    @Test
+    public void testReaderDelta_firstTime() throws IOException {
+        int uid = 42;
+        setupDirectory(
+                mProcDirectory.toPath().resolve(String.valueOf(uid)),
+                new int[]{42, 1, 2, 3},
+                new int[]{1000, 2000},
+                // Units are 10ms aka 10000Us
+                new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+
+        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+                mProcDirectory.toPath(), uid);
+        reader.setBinderThreadNativeTids(new int[]{1, 3});
+        SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+                reader.readDelta();
+        assertArrayEquals(new long[]{100 * 10000, 1100 * 10000},
+                systemServiceCpuThreadTimes.threadCpuTimesUs);
+        assertArrayEquals(new long[]{0, 600 * 10000},
+                systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+    }
+
+    @Test
+    public void testReaderDelta_nextTime() throws IOException {
+        int uid = 42;
+        setupDirectory(
+                mProcDirectory.toPath().resolve(String.valueOf(uid)),
+                new int[]{42, 1, 2, 3},
+                new int[]{1000, 2000},
+                new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+
+        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+                mProcDirectory.toPath(), uid);
+        reader.setBinderThreadNativeTids(new int[]{1, 3});
+
+        // First time, populate "last" snapshot
+        reader.readDelta();
+
+        FileUtils.deleteContents(mProcDirectory);
+        setupDirectory(
+                mProcDirectory.toPath().resolve(String.valueOf(uid)),
+                new int[]{42, 1, 2, 3},
+                new int[]{1000, 2000},
+                new int[][]{{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}});
+
+        // Second time, get the actual delta
+        SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+                reader.readDelta();
+
+        assertArrayEquals(new long[]{3100 * 10000, 2500 * 10000},
+                systemServiceCpuThreadTimes.threadCpuTimesUs);
+        assertArrayEquals(new long[]{1800 * 10000, 1400 * 10000},
+                systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+    }
+
+    private void setupDirectory(Path processPath, int[] threadIds, int[] cpuFrequencies,
+            int[][] cpuTimes) throws IOException {
+        // Make /proc/$PID
+        assertTrue(processPath.toFile().mkdirs());
+
+        // Make /proc/$PID/task
+        final Path selfThreadsPath = processPath.resolve("task");
+        assertTrue(selfThreadsPath.toFile().mkdirs());
+
+        // Make thread directories in reverse order, as they are read in order of creation by
+        // CpuThreadProcReader
+        for (int i = 0; i < threadIds.length; i++) {
+            // Make /proc/$PID/task/$TID
+            final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+            assertTrue(threadPath.toFile().mkdirs());
+
+            // Make /proc/$PID/task/$TID/time_in_state
+            final OutputStream timeInStateStream =
+                    Files.newOutputStream(threadPath.resolve("time_in_state"));
+            for (int j = 0; j < cpuFrequencies.length; j++) {
+                final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
+                timeInStateStream.write(line.getBytes());
+            }
+            timeInStateStream.close();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
new file mode 100644
index 0000000..ac5443e
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Process;
+
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemServicePowerCalculatorTest {
+
+    private PowerProfile mProfile;
+    private MockBatteryStatsImpl mMockBatteryStats;
+    private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
+    private MockServerCpuThreadReader mMockServerCpuThreadReader;
+    private SystemServicePowerCalculator mSystemServicePowerCalculator;
+
+    @Before
+    public void setUp() throws IOException {
+        Context context = InstrumentationRegistry.getContext();
+        mProfile = new PowerProfile(context, true /* forTest */);
+        mMockServerCpuThreadReader = new MockServerCpuThreadReader();
+        mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
+        mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks())
+                .setPowerProfile(mProfile)
+                .setSystemServerCpuThreadReader(mMockServerCpuThreadReader)
+                .setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
+                .setUserInfoProvider(new MockUserInfoProvider());
+        mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
+        mSystemServicePowerCalculator =
+                new SystemServicePowerCalculator(mProfile, mMockBatteryStats);
+    }
+
+    @Test
+    public void testCalculateApp() {
+        // Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
+        mMockServerCpuThreadReader.setThreadTimes(
+                new long[]{30000, 40000, 50000, 60000, 70000, 80000, 90000},
+                new long[]{20000, 30000, 40000, 50000, 60000, 70000, 80000});
+
+        mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
+                new long[]{10000, 20000, 30000, 40000, 50000, 60000, 70000}
+        );
+
+        mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
+
+        int workSourceUid1 = 100;
+        int workSourceUid2 = 200;
+        int transactionCode = 42;
+
+        Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+        BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(workSourceUid1,
+                Binder.class, transactionCode, true /*screenInteractive */);
+        stat1.incrementalCallCount = 100;
+        stat1.recordedCallCount = 100;
+        stat1.cpuTimeMicros = 1000000;
+        callStats.add(stat1);
+
+        mMockBatteryStats.noteBinderCallStats(workSourceUid1, 100, callStats, null);
+
+        callStats.clear();
+        BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(workSourceUid2,
+                Binder.class, transactionCode, true /*screenInteractive */);
+        stat2.incrementalCallCount = 100;
+        stat2.recordedCallCount = 100;
+        stat2.cpuTimeMicros = 9000000;
+        callStats.add(stat2);
+
+        mMockBatteryStats.noteBinderCallStats(workSourceUid2, 100, callStats, null);
+
+        mMockBatteryStats.updateSystemServiceCallStats();
+        mMockBatteryStats.updateSystemServerThreadStats();
+
+        BatterySipper app1 = new BatterySipper(BatterySipper.DrainType.APP,
+                mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
+        mSystemServicePowerCalculator.calculateApp(app1, app1.uidObj, 0, 0,
+                BatteryStats.STATS_SINCE_CHARGED);
+        assertEquals(0.27162, app1.systemServiceCpuPowerMah, 0.00001);
+
+        BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
+                mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
+        mSystemServicePowerCalculator.calculateApp(app2, app2.uidObj, 0, 0,
+                BatteryStats.STATS_SINCE_CHARGED);
+        assertEquals(2.44458, app2.systemServiceCpuPowerMah, 0.00001);
+    }
+
+    private static class MockKernelCpuUidFreqTimeReader extends
+            KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader {
+        private long[] mSystemServerCpuTimes;
+
+        MockKernelCpuUidFreqTimeReader() {
+            super(/*throttle */false);
+        }
+
+        void setSystemServerCpuTimes(long[] systemServerCpuTimes) {
+            mSystemServerCpuTimes = systemServerCpuTimes;
+        }
+
+        @Override
+        public boolean perClusterTimesAvailable() {
+            return true;
+        }
+
+        @Override
+        public void readDelta(@Nullable Callback<long[]> cb) {
+            if (cb != null) {
+                cb.onUidCpuTime(Process.SYSTEM_UID, mSystemServerCpuTimes);
+            }
+        }
+    }
+
+    private static class MockServerCpuThreadReader extends SystemServerCpuThreadReader {
+        private SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
+
+        MockServerCpuThreadReader() {
+            super(null);
+        }
+
+        public void setThreadTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
+            mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
+            mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
+        }
+
+        @Override
+        public SystemServiceCpuThreadTimes readDelta() {
+            return mThreadTimes;
+        }
+    }
+
+    private static class MockUserInfoProvider extends BatteryStatsImpl.UserInfoProvider {
+        @Nullable
+        @Override
+        protected int[] getUserIds() {
+            return new int[0];
+        }
+
+        @Override
+        public boolean exists(int userId) {
+            return true;
+        }
+    }
+}
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 4cdfbb8..5711f98 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -415,6 +415,7 @@
 key usage 0x0c0067 WINDOW
 key usage 0x0c006F BRIGHTNESS_UP
 key usage 0x0c0070 BRIGHTNESS_DOWN
+key usage 0x0c0173 MEDIA_AUDIO_TRACK
 
 # Joystick and game controller axes.
 # Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
diff --git a/data/keyboards/Vendor_2dc8_Product_6101.kl b/data/keyboards/Vendor_2dc8_Product_6101.kl
new file mode 100644
index 0000000..ec9f558
--- /dev/null
+++ b/data/keyboards/Vendor_2dc8_Product_6101.kl
@@ -0,0 +1,55 @@
+# 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.
+
+#
+# 8BitDo - SN30 Pro gamepad in Android (D-Input) mode
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Button labeled as "A" but should really produce keycode "B"
+key 304      BUTTON_B
+# Button labeled as "B" but should really produce keycode "A"
+key 305      BUTTON_A
+# Button labeled as "X" but should really produce keycode "Y"
+key 307      BUTTON_Y
+# Button labeled as "Y" but should really produce keycode "X"
+key 308      BUTTON_X
+
+key 310      BUTTON_L1
+key 312      BUTTON_L2
+key 311      BUTTON_R1
+key 313      BUTTON_R2
+
+# Button "Start" does not emit event when gamepad is in Android mode
+# Button "Home"
+key 306      BUTTON_MODE
+key 314      BUTTON_SELECT
+key 315      BUTTON_START
+
+key 317      BUTTON_THUMBL
+key 318      BUTTON_THUMBR
+
+# Left Analog Stick
+axis 0x00    X
+axis 0x01    Y
+
+# Right Analog Stick
+axis 0x02    Z
+axis 0x05    RZ
+
+# Dpad
+axis 0x10    HAT_X
+axis 0x11    HAT_Y
+
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 3893041..8ab7da5 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -101,7 +101,7 @@
         },
     },
     sanitize: {
-        blacklist: "libandroidfw_blacklist.txt",
+        blocklist: "libandroidfw_blocklist.txt",
     },
 }
 
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index e351a46..e10a7f3 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1717,6 +1717,10 @@
     // The overlay must be signed with the same signature as the actor declared for the target
     // resource
     ACTOR_SIGNATURE = 0x00000080,
+
+    // The overlay must be signed with the same signature as the reference package declared
+    // in the SystemConfig
+    CONFIG_SIGNATURE = 0x00000100,
   };
 
   using PolicyBitmask = uint32_t;
diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blocklist.txt
similarity index 100%
rename from libs/androidfw/libandroidfw_blacklist.txt
rename to libs/androidfw/libandroidfw_blocklist.txt
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index b933813..12e2e81 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -16,14 +16,14 @@
 
 #include "android/graphics/jni_runtime.h"
 
-#include <android/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <sys/cdefs.h>
-
 #include <EGL/egl.h>
 #include <GraphicsJNI.h>
 #include <Properties.h>
 #include <SkGraphics.h>
+#include <android/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <sys/cdefs.h>
+#include <vulkan/vulkan.h>
 
 #undef LOG_TAG
 #define LOG_TAG "AndroidGraphicsJNI"
@@ -172,6 +172,11 @@
 
 void zygote_preload_graphics() {
     if (Properties::peekRenderPipelineType() == RenderPipelineType::SkiaGL) {
+        // Preload GL driver if HWUI renders with GL backend.
         eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    } else {
+        // Preload Vulkan driver if HWUI renders with Vulkan backend.
+        uint32_t apiVersion;
+        vkEnumerateInstanceVersion(&apiVersion);
     }
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 0f68376..e76aace 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -228,9 +228,12 @@
 
 static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
     ScopedUtfChars strSksl(env, sksl);
-    sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str())));
-    ThrowIAE_IfNull(env, effect);
-
+    auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()));
+    sk_sp<SkRuntimeEffect> effect = std::get<0>(result);
+    if (!effect) {
+        const auto& err = std::get<1>(result);
+        doThrowIAE(env, err.c_str());
+    }
     return reinterpret_cast<jlong>(effect.release());
 }
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index bea6121..565fb61 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -162,7 +162,6 @@
 }
 
 void RenderThread::initThreadLocals() {
-    HardwareBitmapUploader::initialize();
     setupFrameInterval();
     initializeChoreographer();
     mEglManager = new EglManager();
@@ -391,12 +390,10 @@
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
         std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); });
         eglInitThread.detach();
+    } else {
+        requireVkContext();
     }
-    // TODO: uncomment only after http://b/135536511 is fixed.
-    // else {
-    //    uint32_t apiVersion;
-    //    vkEnumerateInstanceVersion(&apiVersion);
-    //}
+    HardwareBitmapUploader::initialize();
 }
 
 } /* namespace renderthread */
diff --git a/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java
index b2f9a0f..23977f1 100644
--- a/location/java/android/location/GnssAntennaInfo.java
+++ b/location/java/android/location/GnssAntennaInfo.java
@@ -53,7 +53,7 @@
      * Class containing information about the antenna phase center offset (PCO). PCO is defined with
      * respect to the origin of the Android sensor coordinate system, e.g., center of primary screen
      * for mobiles - see sensor or form factor documents for details. Uncertainties are reported
-     *  to 1-sigma.
+     * to 1-sigma.
      */
     public static final class PhaseCenterOffset implements Parcelable {
         private final double mOffsetXMm;
@@ -95,31 +95,55 @@
                     }
                 };
 
+        /**
+         * Returns the x-axis offset of the phase center from the origin of the Android sensor
+         * coordinate system, in millimeters.
+         */
         @FloatRange()
         public double getXOffsetMm() {
             return mOffsetXMm;
         }
 
+        /**
+         * Returns the 1-sigma uncertainty of the x-axis offset of the phase center from the origin
+         * of the Android sensor coordinate system, in millimeters.
+         */
         @FloatRange()
         public double getXOffsetUncertaintyMm() {
             return mOffsetXUncertaintyMm;
         }
 
+        /**
+         * Returns the y-axis offset of the phase center from the origin of the Android sensor
+         * coordinate system, in millimeters.
+         */
         @FloatRange()
         public double getYOffsetMm() {
             return mOffsetYMm;
         }
 
+        /**
+         * Returns the 1-sigma uncertainty of the y-axis offset of the phase center from the origin
+         * of the Android sensor coordinate system, in millimeters.
+         */
         @FloatRange()
         public double getYOffsetUncertaintyMm() {
             return mOffsetYUncertaintyMm;
         }
 
+        /**
+         * Returns the z-axis offset of the phase center from the origin of the Android sensor
+         * coordinate system, in millimeters.
+         */
         @FloatRange()
         public double getZOffsetMm() {
             return mOffsetZMm;
         }
 
+        /**
+         * Returns the 1-sigma uncertainty of the z-axis offset of the phase center from the origin
+         * of the Android sensor coordinate system, in millimeters.
+         */
         @FloatRange()
         public double getZOffsetUncertaintyMm() {
             return mOffsetZUncertaintyMm;
@@ -165,7 +189,7 @@
      * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
      * i.e., deltaPhi = 180 / (number of columns - 1).
      */
-    public static final class SphericalCorrections implements Parcelable{
+    public static final class SphericalCorrections implements Parcelable {
         private final double[][] mCorrections;
         private final double[][] mCorrectionUncertainties;
         private final double mDeltaTheta;
@@ -296,10 +320,10 @@
         public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeInt(mNumRows);
             dest.writeInt(mNumColumns);
-            for (double[] row: mCorrections) {
+            for (double[] row : mCorrections) {
                 dest.writeDoubleArray(row);
             }
-            for (double[] row: mCorrectionUncertainties) {
+            for (double[] row : mCorrectionUncertainties) {
                 dest.writeDoubleArray(row);
             }
         }
@@ -340,6 +364,7 @@
 
         /**
          * Set antenna carrier frequency (MHz).
+         *
          * @param carrierFrequencyMHz antenna carrier frequency (MHz)
          * @return Builder builder object
          */
@@ -351,6 +376,7 @@
 
         /**
          * Set antenna phase center offset.
+         *
          * @param phaseCenterOffset phase center offset object
          * @return Builder builder object
          */
@@ -362,6 +388,7 @@
 
         /**
          * Set phase center variation corrections.
+         *
          * @param phaseCenterVariationCorrections phase center variation corrections object
          * @return Builder builder object
          */
@@ -374,6 +401,7 @@
 
         /**
          * Set signal gain corrections.
+         *
          * @param signalGainCorrections signal gain corrections object
          * @return Builder builder object
          */
@@ -386,6 +414,7 @@
 
         /**
          * Build GnssAntennaInfo object.
+         *
          * @return instance of GnssAntennaInfo
          */
         @NonNull
@@ -400,47 +429,65 @@
         return mCarrierFrequencyMHz;
     }
 
+    /**
+     * Returns a {@link PhaseCenterOffset} object encapsulating the phase center offset and
+     * corresponding uncertainties in millimeters.
+     *
+     * @return {@link PhaseCenterOffset}
+     */
     @NonNull
     public PhaseCenterOffset getPhaseCenterOffset() {
         return mPhaseCenterOffset;
     }
 
+    /**
+     * Returns a {@link SphericalCorrections} object encapsulating the phase center variation
+     * corrections and corresponding uncertainties in millimeters.
+     *
+     * @return phase center variation corrections as {@link SphericalCorrections}
+     */
     @Nullable
     public SphericalCorrections getPhaseCenterVariationCorrections() {
         return mPhaseCenterVariationCorrections;
     }
 
+    /**
+     * Returns a {@link SphericalCorrections} object encapsulating the signal gain
+     * corrections and corresponding uncertainties in dBi.
+     *
+     * @return signal gain corrections as {@link SphericalCorrections}
+     */
     @Nullable
     public SphericalCorrections getSignalGainCorrections() {
         return mSignalGainCorrections;
     }
 
-    public static final @android.annotation.NonNull
-                    Creator<GnssAntennaInfo> CREATOR = new Creator<GnssAntennaInfo>() {
-                            @Override
-                            public GnssAntennaInfo createFromParcel(Parcel in) {
-                                double carrierFrequencyMHz = in.readDouble();
+    public static final @android.annotation.NonNull Creator<GnssAntennaInfo> CREATOR =
+            new Creator<GnssAntennaInfo>() {
+                @Override
+                public GnssAntennaInfo createFromParcel(Parcel in) {
+                    double carrierFrequencyMHz = in.readDouble();
 
-                                ClassLoader classLoader = getClass().getClassLoader();
-                                PhaseCenterOffset phaseCenterOffset =
-                                        in.readParcelable(classLoader);
-                                SphericalCorrections phaseCenterVariationCorrections =
-                                        in.readParcelable(classLoader);
-                                SphericalCorrections signalGainCorrections =
-                                        in.readParcelable(classLoader);
+                    ClassLoader classLoader = getClass().getClassLoader();
+                    PhaseCenterOffset phaseCenterOffset =
+                            in.readParcelable(classLoader);
+                    SphericalCorrections phaseCenterVariationCorrections =
+                            in.readParcelable(classLoader);
+                    SphericalCorrections signalGainCorrections =
+                            in.readParcelable(classLoader);
 
-                                return new GnssAntennaInfo(
-                                            carrierFrequencyMHz,
-                                            phaseCenterOffset,
-                                            phaseCenterVariationCorrections,
-                                            signalGainCorrections);
-                            }
+                    return new GnssAntennaInfo(
+                            carrierFrequencyMHz,
+                            phaseCenterOffset,
+                            phaseCenterVariationCorrections,
+                            signalGainCorrections);
+                }
 
-                            @Override
-                            public GnssAntennaInfo[] newArray(int size) {
-                                return new GnssAntennaInfo[size];
-                            }
-                    };
+                @Override
+                public GnssAntennaInfo[] newArray(int size) {
+                    return new GnssAntennaInfo[size];
+                }
+            };
 
     @Override
     public int describeContents() {
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index 542737b4..ef68814 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -21,6 +21,8 @@
 import android.annotation.Nullable;
 import android.location.util.identity.CallerIdentity;
 
+import java.util.List;
+
 /**
  * Location manager local system service interface.
  *
@@ -29,6 +31,16 @@
 public abstract class LocationManagerInternal {
 
     /**
+     * Listener for changes in provider enabled state.
+     */
+    public interface ProviderEnabledListener {
+        /**
+         * Called when the provider enabled state changes for a particular user.
+         */
+        void onProviderEnabledChanged(String provider, int userId, boolean enabled);
+    }
+
+    /**
      * Returns true if the given provider is enabled for the given user.
      *
      * @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
@@ -38,6 +50,24 @@
     public abstract boolean isProviderEnabledForUser(@NonNull String provider, int userId);
 
     /**
+     * Adds a provider enabled listener. The given provider must exist.
+     *
+     * @param provider The provider to listen for changes
+     * @param listener The listener
+     */
+    public abstract void addProviderEnabledListener(String provider,
+            ProviderEnabledListener listener);
+
+    /**
+     * Removes a provider enabled listener. The given provider must exist.
+     *
+     * @param provider The provider to listen for changes
+     * @param listener The listener
+     */
+    public abstract void removeProviderEnabledListener(String provider,
+            ProviderEnabledListener listener);
+
+    /**
      * Returns true if the given identity is a location provider.
      *
      * @param provider The provider to check, or null to check every provider
@@ -52,4 +82,10 @@
      */
     // TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
     public abstract void sendNiResponse(int notifId, int userResponse);
+
+    /**
+     * Should only be used by GNSS code.
+     */
+    // TODO: there is no reason for this to exist as part of any API. create a real batching API
+    public abstract void reportGnssBatchLocations(List<Location> locations);
 }
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index bb36c2a..280bd05 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -32,6 +32,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Objects;
+
 
 /**
  * A data object that contains quality of service parameters for requests
@@ -150,8 +152,6 @@
 
     @UnsupportedAppUsage
     private String mProvider;
-    // if true, client requests coarse location, if false, client requests fine location
-    private boolean mCoarseLocation;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mQuality;
     @UnsupportedAppUsage
@@ -257,7 +257,6 @@
     public LocationRequest() {
         this(
                 /* provider= */ LocationManager.FUSED_PROVIDER,
-                /* coarseLocation= */ false,
                 /* quality= */ POWER_LOW,
                 /* interval= */ DEFAULT_INTERVAL_MS,
                 /* fastestInterval= */ (long) (DEFAULT_INTERVAL_MS / FASTEST_INTERVAL_FACTOR),
@@ -276,7 +275,6 @@
     public LocationRequest(LocationRequest src) {
         this(
                 src.mProvider,
-                src.mCoarseLocation,
                 src.mQuality,
                 src.mInterval,
                 src.mFastestInterval,
@@ -293,7 +291,6 @@
 
     private LocationRequest(
             @NonNull String provider,
-            boolean coarseLocation,
             int quality,
             long intervalMs,
             long fastestIntervalMs,
@@ -310,7 +307,6 @@
         checkQuality(quality);
 
         mProvider = provider;
-        mCoarseLocation = coarseLocation;
         mQuality = quality;
         mInterval = intervalMs;
         mFastestInterval = fastestIntervalMs;
@@ -327,20 +323,6 @@
     }
 
     /**
-     * @hide
-     */
-    public boolean isCoarse() {
-        return mCoarseLocation;
-    }
-
-    /**
-     * @hide
-     */
-    public void setCoarse(boolean coarse) {
-        mCoarseLocation = coarse;
-    }
-
-    /**
      * Set the quality of the request.
      *
      * <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power
@@ -720,7 +702,6 @@
                 public LocationRequest createFromParcel(Parcel in) {
                     return new LocationRequest(
                             /* provider= */ in.readString(),
-                            /* coarseLocation= */ in.readBoolean(),
                             /* quality= */ in.readInt(),
                             /* interval= */ in.readLong(),
                             /* fastestInterval= */ in.readLong(),
@@ -749,7 +730,6 @@
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mProvider);
-        parcel.writeBoolean(mCoarseLocation);
         parcel.writeInt(mQuality);
         parcel.writeLong(mInterval);
         parcel.writeLong(mFastestInterval);
@@ -784,6 +764,36 @@
         }
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        LocationRequest that = (LocationRequest) o;
+        return mQuality == that.mQuality
+                && mInterval == that.mInterval
+                && mFastestInterval == that.mFastestInterval
+                && mExplicitFastestInterval == that.mExplicitFastestInterval
+                && mExpireAt == that.mExpireAt
+                && mExpireIn == that.mExpireIn
+                && mNumUpdates == that.mNumUpdates
+                && Float.compare(that.mSmallestDisplacement, mSmallestDisplacement) == 0
+                && mHideFromAppOps == that.mHideFromAppOps
+                && mLocationSettingsIgnored == that.mLocationSettingsIgnored
+                && mLowPowerMode == that.mLowPowerMode
+                && mProvider.equals(that.mProvider)
+                && Objects.equals(mWorkSource, that.mWorkSource);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mProvider, mInterval, mWorkSource);
+    }
+
     @NonNull
     @Override
     public String toString() {
@@ -794,7 +804,7 @@
         if (mQuality != POWER_NONE) {
             s.append(" interval=");
             TimeUtils.formatDuration(mInterval, s);
-            if (mExplicitFastestInterval) {
+            if (mExplicitFastestInterval && mFastestInterval != mInterval) {
                 s.append(" fastestInterval=");
                 TimeUtils.formatDuration(mFastestInterval, s);
             }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3ac71b2..408f34b 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -564,6 +564,7 @@
      * request is from a hardware key press. (e.g. {@link MediaController}).
      * @hide
      */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int FLAG_FROM_KEY = 1 << 12;
 
     // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
@@ -3801,7 +3802,7 @@
         final IAudioService service = getService();
         try {
             service.unregisterAudioPolicyAsync(policy.cb());
-            policy.setRegistration(null);
+            policy.reset();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3823,7 +3824,7 @@
         try {
             policy.invalidateCaptorsAndInjectors();
             service.unregisterAudioPolicy(policy.cb());
-            policy.setRegistration(null);
+            policy.reset();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4600,36 +4601,41 @@
     /**
      * @hide
      * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
-     * an argument to {@link #setDeviceVolumeBehavior(int, String, int)}.
+     * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
+     * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
      */
     public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
     /**
      * @hide
      * Volume behavior for an audio device where a software attenuation is applied
-     * @see #setDeviceVolumeBehavior(int, String, int)
+     * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
      */
+    @SystemApi
     public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
     /**
      * @hide
      * Volume behavior for an audio device where the volume is always set to provide no attenuation
      *     nor gain (e.g. unit gain).
-     * @see #setDeviceVolumeBehavior(int, String, int)
+     * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
      */
+    @SystemApi
     public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
     /**
      * @hide
      * Volume behavior for an audio device where the volume is either set to muted, or to provide
      *     no attenuation nor gain (e.g. unit gain).
-     * @see #setDeviceVolumeBehavior(int, String, int)
+     * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
      */
+    @SystemApi
     public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
     /**
      * @hide
      * Volume behavior for an audio device where no software attenuation is applied, and
      *     the volume is kept synchronized between the host and the device itself through a
      *     device-specific protocol such as BT AVRCP.
-     * @see #setDeviceVolumeBehavior(int, String, int)
+     * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
      */
+    @SystemApi
     public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
     /**
      * @hide
@@ -4638,8 +4644,9 @@
      *     device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
      *     normal vs in phone call).
      * @see #setMode(int)
-     * @see #setDeviceVolumeBehavior(int, String, int)
+     * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
      */
+    @SystemApi
     public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
 
     /** @hide */
@@ -4686,27 +4693,15 @@
     /**
      * @hide
      * Sets the volume behavior for an audio output device.
-     * @param deviceType the type of audio device to be affected. Currently only supports
-     *     {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
-     *     {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
-     * @param deviceAddress the address of the device, if any
+     * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
+     * @see #DEVICE_VOLUME_BEHAVIOR_FULL
+     * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
+     * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
+     * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
+     * @param device the device to be affected
      * @param deviceVolumeBehavior one of the device behaviors
      */
-    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public void setDeviceVolumeBehavior(int deviceType, @Nullable String deviceAddress,
-            @DeviceVolumeBehavior int deviceVolumeBehavior) {
-        setDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
-                deviceType, deviceAddress), deviceVolumeBehavior);
-    }
-
-    /**
-     * @hide
-     * Sets the volume behavior for an audio output device.
-     * @param device the device to be affected. Currently only supports devices of type
-     *     {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
-     *     {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
-     * @param deviceVolumeBehavior one of the device behaviors
-     */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
             @DeviceVolumeBehavior int deviceVolumeBehavior) {
@@ -4725,29 +4720,14 @@
 
     /**
      * @hide
-     * Returns the volume device behavior for the given device type and address
-     * @param deviceType an audio output device type, as defined in {@link AudioDeviceInfo}
-     * @param deviceAddress the address of the audio device, if any.
-     * @return the volume behavior for the device
-     */
-    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(int deviceType,
-            @Nullable String deviceAddress) {
-        // verify arguments
-        AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType);
-        return getDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
-                deviceType, deviceAddress));
-    }
-
-    /**
-     * @hide
      * Returns the volume device behavior for the given audio device
      * @param device the audio device
      * @return the volume behavior for the device
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
-            @NonNull AudioDeviceAttributes device) {
+    public @DeviceVolumeBehavior
+    int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
         // verify arguments (validity of device type is enforced in server)
         Objects.requireNonNull(device);
         // communicate with service
@@ -6200,6 +6180,24 @@
         }
     }
 
+
+    /**
+     * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
+     * For more details on Hardware A/V synchronization please refer to
+     *  <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
+     * media tunneling documentation</a>.
+     * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
+     * @return the HW A/V sync ID for this audio session (an integer different from 0).
+     * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
+     */
+    public int getAudioHwSyncForSession(int sessionId) {
+        int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
+        if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
+            throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
+        }
+        return hwSyncId;
+    }
+
     //---------------------------------------------------------
     // Inner classes
     //--------------------
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4d26b8d..c9cdbb0 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -487,6 +487,11 @@
         }
     }
 
+    /** @hide */
+    public AudioAttributes getAudioAttributes() {
+        return mAudioAttributes;
+    }
+
     /**
      * Builder class for {@link AudioRecord} objects.
      * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 87c3bb9..5dc6f75 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -198,7 +198,10 @@
      *   {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
      * </tr>
      * </table>
-     * Using other combinations may result in {@link IllegalArgumentException}.
+     * Using other combinations may result in {@link IllegalArgumentException}. Additionally,
+     * specifying {@link HardwareBuffer#USAGE_CPU_WRITE_RARELY} or
+     * {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} and writing to the ImageReader's buffers
+     * might break assumptions made by some producers, and should be used with caution.
      * </p>
      * <p>
      * If the {@link ImageReader} is used as an output target for a {@link
@@ -255,6 +258,7 @@
         mWidth = width;
         mHeight = height;
         mFormat = format;
+        mUsage = usage;
         mMaxImages = maxImages;
 
         if (width < 1 || height < 1) {
@@ -768,6 +772,7 @@
     private final int mWidth;
     private final int mHeight;
     private final int mFormat;
+    private final long mUsage;
     private final int mMaxImages;
     private final int mNumPlanes;
     private final Surface mSurface;
@@ -909,7 +914,8 @@
             throwISEIfImageIsInvalid();
 
             if (mPlanes == null) {
-                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
+                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat,
+                        ImageReader.this.mUsage);
             }
             // Shallow copy is fine.
             return mPlanes.clone();
@@ -1038,7 +1044,7 @@
         private AtomicBoolean mIsDetached = new AtomicBoolean(false);
 
         private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
-                int readerFormat);
+                int readerFormat, long readerUsage);
         private synchronized native int nativeGetWidth();
         private synchronized native int nativeGetHeight();
         private synchronized native int nativeGetFormat(int readerFormat);
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index d3e9c7e..8a17465 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -553,6 +553,12 @@
         }
     }
 
+    /** @hide */
+    public void reset() {
+        setRegistration(null);
+        mConfig.reset();
+    }
+
     public void setRegistration(String regId) {
         synchronized (mLock) {
             mRegistrationId = regId;
@@ -566,6 +572,11 @@
         sendMsg(MSG_POLICY_STATUS_CHANGE);
     }
 
+    /**@hide*/
+    public String getRegistration() {
+        return mRegistrationId;
+    }
+
     private boolean policyReadyToUse() {
         synchronized (mLock) {
             if (mStatus != POLICY_STATUS_REGISTERED) {
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 91b9bb3..561a884 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -162,7 +162,7 @@
 
     public String toLogFriendlyString () {
         String textDump = new String("android.media.audiopolicy.AudioPolicyConfig:\n");
-        textDump += mMixes.size() + " AudioMix: "+ mRegistrationId + "\n";
+        textDump += mMixes.size() + " AudioMix, reg:" + mRegistrationId + "\n";
         for(AudioMix mix : mMixes) {
             // write mix route flags
             textDump += "* route flags=0x" + Integer.toHexString(mix.getRouteFlags()) + "\n";
@@ -220,6 +220,10 @@
         return textDump;
     }
 
+    protected void reset() {
+        mMixCounter = 0;
+    }
+
     protected void setRegistration(String regId) {
         final boolean currentRegNull = (mRegistrationId == null) || mRegistrationId.isEmpty();
         final boolean newRegNull = (regId == null) || regId.isEmpty();
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 0a02156..bd2a0eaa7 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -675,7 +675,8 @@
     return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
 }
 
-static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
+static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image,
+        uint64_t ndkReaderUsage) {
     ALOGV("%s", __FUNCTION__);
     BufferItem* buffer = Image_getBufferItem(env, thiz);
     if (buffer == NULL) {
@@ -684,8 +685,16 @@
         return;
     }
 
-    status_t res = lockImageFromBuffer(buffer,
-            GRALLOC_USAGE_SW_READ_OFTEN, buffer->mFence->dup(), image);
+    uint32_t lockUsage;
+    if ((ndkReaderUsage & (AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY
+            | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN)) != 0) {
+        lockUsage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+    } else {
+        lockUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+    }
+
+    status_t res = lockImageFromBuffer(buffer, lockUsage, buffer->mFence->dup(), image);
+
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
                 "lock buffer failed for format 0x%x",
@@ -721,7 +730,7 @@
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
-        int numPlanes, int readerFormat)
+        int numPlanes, int readerFormat, uint64_t ndkReaderUsage)
 {
     ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
     int rowStride = 0;
@@ -754,7 +763,7 @@
     }
 
     LockedImage lockedImg = LockedImage();
-    Image_getLockedImage(env, thiz, &lockedImg);
+    Image_getLockedImage(env, thiz, &lockedImg, ndkReaderUsage);
     if (env->ExceptionCheck()) {
         return NULL;
     }
@@ -839,7 +848,7 @@
 };
 
 static const JNINativeMethod gImageMethods[] = {
-    {"nativeCreatePlanes",      "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
+    {"nativeCreatePlanes",      "(IIJ)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
                                                              (void*)Image_createSurfacePlanes },
     {"nativeGetWidth",          "()I",                       (void*)Image_getWidth },
     {"nativeGetHeight",         "()I",                       (void*)Image_getHeight },
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 033a32f..55aac09 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -590,7 +590,7 @@
     ALOGV("getSyncSettings: %d %d %f %f",
             scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
 
-    // sanity check params
+    // check params
     if (scp.sync.mSource >= AVSYNC_SOURCE_MAX
             || scp.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
             || scp.sync.mTolerance < 0.f
diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
index f752008..d1ce30a 100644
--- a/media/jni/android_media_MediaSync.cpp
+++ b/media/jni/android_media_MediaSync.cpp
@@ -451,7 +451,7 @@
     ALOGV("getSyncParams: %d %d %f %f",
             scs.sync.mSource, scs.sync.mAudioAdjustMode, scs.sync.mTolerance, scs.frameRate);
 
-    // sanity check params
+    // check params
     if (scs.sync.mSource >= AVSYNC_SOURCE_MAX
             || scs.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
             || scs.sync.mTolerance < 0.f
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 3cd4081..5770c67 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -291,8 +291,9 @@
 C2DataIdInfo::C2DataIdInfo(uint32_t index, uint64_t value) : C2Param(kParamSize, index) {
     CHECK(isGlobal());
     CHECK_EQ(C2Param::INFO, kind());
-    DummyInfo info{value};
-    memcpy(this + 1, static_cast<C2Param *>(&info) + 1, kParamSize - sizeof(C2Param));
+    mInfo = StubInfo(value);
+    memcpy(static_cast<C2Param *>(this) + 1, static_cast<C2Param *>(&mInfo) + 1,
+            kParamSize - sizeof(C2Param));
 }
 
 /////////////// MediaEvent ///////////////////////
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 83e9db7..fd29959 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -250,8 +250,9 @@
 public:
     C2DataIdInfo(uint32_t index, uint64_t value);
 private:
-    typedef C2GlobalParam<C2Info, C2Int64Value, 0> DummyInfo;
-    static const size_t kParamSize = sizeof(DummyInfo);
+    typedef C2GlobalParam<C2Info, C2Int64Value, 0> StubInfo;
+    StubInfo mInfo;
+    static const size_t kParamSize = sizeof(StubInfo);
 };
 
 }  // namespace android
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index f4d65d0..a74ae53 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -34,21 +34,9 @@
 
 // ---------------------------------------------------------------------------
 
-Visualizer::Visualizer (const String16& opPackageName,
-         int32_t priority,
-         effect_callback_t cbf,
-         void* user,
-         audio_session_t sessionId)
-    :   AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
-        mCaptureRate(CAPTURE_RATE_DEF),
-        mCaptureSize(CAPTURE_SIZE_DEF),
-        mSampleRate(44100000),
-        mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
-        mMeasurementMode(MEASUREMENT_MODE_NONE),
-        mCaptureCallBack(NULL),
-        mCaptureCbkUser(NULL)
+Visualizer::Visualizer (const String16& opPackageName)
+        :   AudioEffect(opPackageName)
 {
-    initCaptureSize();
 }
 
 Visualizer::~Visualizer()
@@ -58,6 +46,23 @@
     setCaptureCallBack(NULL, NULL, 0, 0);
 }
 
+status_t Visualizer::set(int32_t priority,
+                         effect_callback_t cbf,
+                         void* user,
+                         audio_session_t sessionId,
+                         audio_io_handle_t io,
+                         const AudioDeviceTypeAddr& device,
+                         bool probe)
+{
+    status_t status = AudioEffect::set(
+            SL_IID_VISUALIZATION, nullptr, priority, cbf, user, sessionId, io, device, probe);
+    if (status == NO_ERROR || status == ALREADY_EXISTS) {
+        initCaptureSize();
+    }
+    return status;
+}
+
+
 void Visualizer::release()
 {
     ALOGV("Visualizer::release()");
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
index d4672a9..8b6a62f 100644
--- a/media/jni/audioeffect/Visualizer.h
+++ b/media/jni/audioeffect/Visualizer.h
@@ -65,14 +65,22 @@
     /* Constructor.
      * See AudioEffect constructor for details on parameters.
      */
-                        Visualizer(const String16& opPackageName,
-                                   int32_t priority = 0,
-                                   effect_callback_t cbf = NULL,
-                                   void* user = NULL,
-                                   audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
+                        explicit Visualizer(const String16& opPackageName);
 
                         ~Visualizer();
 
+    /**
+     * Initialize an uninitialized Visualizer.
+     * See AudioEffect 'set' function for details on parameters.
+     */
+    status_t    set(int32_t priority = 0,
+                    effect_callback_t cbf = NULL,
+                    void* user = NULL,
+                    audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+                    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+                    const AudioDeviceTypeAddr& device = {},
+                    bool probe = false);
+
     // Declared 'final' because we call this in ~Visualizer().
     status_t    setEnabled(bool enabled) final;
 
@@ -163,15 +171,15 @@
     uint32_t initCaptureSize();
 
     Mutex mCaptureLock;
-    uint32_t mCaptureRate;
-    uint32_t mCaptureSize;
-    uint32_t mSampleRate;
-    uint32_t mScalingMode;
-    uint32_t mMeasurementMode;
-    capture_cbk_t mCaptureCallBack;
-    void *mCaptureCbkUser;
+    uint32_t mCaptureRate = CAPTURE_RATE_DEF;
+    uint32_t mCaptureSize = CAPTURE_SIZE_DEF;
+    uint32_t mSampleRate = 44100000;
+    uint32_t mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
+    uint32_t mMeasurementMode = MEASUREMENT_MODE_NONE;
+    capture_cbk_t mCaptureCallBack = nullptr;
+    void *mCaptureCbkUser = nullptr;
     sp<CaptureThread> mCaptureThread;
-    uint32_t mCaptureFlags;
+    uint32_t mCaptureFlags = 0;
 };
 
 
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index dbe7b4b..96961ac2 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -337,22 +337,21 @@
     }
 
     // create the native AudioEffect object
-    lpAudioEffect = new AudioEffect(typeStr,
-                                    String16(opPackageNameStr.c_str()),
-                                    uuidStr,
-                                    priority,
-                                    effectCallback,
-                                    &lpJniStorage->mCallbackData,
-                                    (audio_session_t) sessionId,
-                                    AUDIO_IO_HANDLE_NONE,
-                                    device,
-                                    probe);
+    lpAudioEffect = new AudioEffect(String16(opPackageNameStr.c_str()));
     if (lpAudioEffect == 0) {
         ALOGE("Error creating AudioEffect");
         goto setup_failure;
     }
 
-
+    lpAudioEffect->set(typeStr,
+                       uuidStr,
+                       priority,
+                       effectCallback,
+                       &lpJniStorage->mCallbackData,
+                       (audio_session_t) sessionId,
+                       AUDIO_IO_HANDLE_NONE,
+                       device,
+                       probe);
     lStatus = AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->initCheck());
     if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
         ALOGE("AudioEffect initCheck failed %d", lStatus);
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index f9a77f4..4c5970a 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -382,15 +382,15 @@
     }
 
     // create the native Visualizer object
-    lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()),
-                                  0,
-                                  android_media_visualizer_effect_callback,
-                                  lpJniStorage,
-                                  (audio_session_t) sessionId);
+    lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()));
     if (lpVisualizer == 0) {
         ALOGE("Error creating Visualizer");
         goto setup_failure;
     }
+    lpVisualizer->set(0,
+                      android_media_visualizer_effect_callback,
+                      lpJniStorage,
+                      (audio_session_t) sessionId);
 
     lStatus = translateError(lpVisualizer->initCheck());
     if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java b/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java
index ce81a18..ab9ae8a 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java
@@ -43,7 +43,7 @@
     public Frame execute(KeyValueMap inputMap) {
         int filterOutCount = mFilter.getNumberOfOutputs();
 
-        // Sanity checks
+        // Validation checks
         if (filterOutCount > 1) {
             throw new RuntimeException("Calling execute on filter " + mFilter + " with multiple "
                 + "outputs! Use executeMulti() instead!");
diff --git a/media/mca/filterfw/jni/jni_native_program.cpp b/media/mca/filterfw/jni/jni_native_program.cpp
index 1424607..cd4f718 100644
--- a/media/mca/filterfw/jni/jni_native_program.cpp
+++ b/media/mca/filterfw/jni/jni_native_program.cpp
@@ -134,7 +134,7 @@
                                                                     jobject output) {
   NativeProgram* program = ConvertFromJava<NativeProgram>(env, thiz);
 
-  // Sanity checks
+  // Validation checks
   if (!program || !inputs) {
     return JNI_FALSE;
   }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 0ae640d..e74bda8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -16,16 +16,6 @@
 
 package com.android.mediaframeworktest.helpers;
 
-import com.android.ex.camera2.blocking.BlockingCameraManager;
-import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
-import com.android.ex.camera2.blocking.BlockingSessionCallback;
-import com.android.ex.camera2.blocking.BlockingStateCallback;
-import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
-
-import junit.framework.Assert;
-
-import org.mockito.Mockito;
-
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.ImageFormat;
@@ -64,6 +54,16 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.ex.camera2.blocking.BlockingCameraManager;
+import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
+import com.android.ex.camera2.blocking.BlockingSessionCallback;
+import com.android.ex.camera2.blocking.BlockingStateCallback;
+import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
+
+import junit.framework.Assert;
+
+import org.mockito.Mockito;
+
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.lang.reflect.Array;
@@ -77,8 +77,8 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
@@ -225,7 +225,7 @@
     }
 
     /**
-     * Dummy listener that release the image immediately once it is available.
+     * Mock listener that release the image immediately once it is available.
      *
      * <p>
      * It can be used for the case where we don't care the image data at all.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java
index 96b0424..a77b289 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java
@@ -22,7 +22,7 @@
 /**
  * Helper set of methods to perform precondition checks before starting method execution.
  *
- * <p>Typically used to sanity check arguments or the current object state.</p>
+ * <p>Typically used to check arguments or the current object state.</p>
  */
 /**
  * (non-Javadoc)
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
index b3f443b..9a64b58 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
@@ -16,7 +16,7 @@
 
 package com.android.mediaframeworktest.helpers;
 
-import junit.framework.Assert;
+import static com.android.mediaframeworktest.helpers.AssertHelpers.assertArrayContainsAnyOf;
 
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
@@ -31,6 +31,8 @@
 import android.util.Rational;
 import android.util.Size;
 
+import junit.framework.Assert;
+
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -40,8 +42,6 @@
 import java.util.List;
 import java.util.Set;
 
-import static com.android.mediaframeworktest.helpers.AssertHelpers.assertArrayContainsAnyOf;
-
 /**
  * Helpers to get common static info out of the camera.
  *
@@ -435,7 +435,7 @@
     }
 
     /**
-     * Get max AE regions and do sanity check.
+     * Get max AE regions and do validation check.
      *
      * @return AE max regions supported by the camera device
      */
@@ -448,7 +448,7 @@
     }
 
     /**
-     * Get max AWB regions and do sanity check.
+     * Get max AWB regions and do validation check.
      *
      * @return AWB max regions supported by the camera device
      */
@@ -461,7 +461,7 @@
     }
 
     /**
-     * Get max AF regions and do sanity check.
+     * Get max AF regions and do validation check.
      *
      * @return AF max regions supported by the camera device
      */
@@ -545,7 +545,7 @@
     }
 
     /**
-     * Get available thumbnail sizes and do the sanity check.
+     * Get available thumbnail sizes and do the  validation check.
      *
      * @return The array of available thumbnail sizes
      */
@@ -573,7 +573,7 @@
     }
 
     /**
-     * Get available focal lengths and do the sanity check.
+     * Get available focal lengths and do the validation check.
      *
      * @return The array of available focal lengths
      */
@@ -594,7 +594,7 @@
     }
 
     /**
-     * Get available apertures and do the sanity check.
+     * Get available apertures and do the validation check.
      *
      * @return The non-null array of available apertures
      */
@@ -909,7 +909,7 @@
     }
 
     /**
-     * Get hyperfocalDistance and do the sanity check.
+     * Get hyperfocalDistance and do the validation check.
      * <p>
      * Note that, this tag is optional, will return -1 if this tag is not
      * available.
@@ -1068,7 +1068,7 @@
     }
 
     /**
-     * get android.control.availableModes and do the sanity check.
+     * get android.control.availableModes and do the validation check.
      *
      * @return available control modes.
      */
@@ -1124,7 +1124,7 @@
     }
 
     /**
-     * Get aeAvailableModes and do the sanity check.
+     * Get aeAvailableModes and do the validation check.
      *
      * <p>Depending on the check level this class has, for WAR or COLLECT levels,
      * If the aeMode list is invalid, return an empty mode array. The the caller doesn't
@@ -1196,7 +1196,7 @@
     }
 
     /**
-     * Get available AWB modes and do the sanity check.
+     * Get available AWB modes and do the validation check.
      *
      * @return array that contains available AWB modes, empty array if awbAvailableModes is
      * unavailable.
@@ -1222,7 +1222,7 @@
     }
 
     /**
-     * Get available AF modes and do the sanity check.
+     * Get available AF modes and do the validation check.
      *
      * @return array that contains available AF modes, empty array if afAvailableModes is
      * unavailable.
@@ -1580,7 +1580,7 @@
     }
 
     /**
-     * Get value of key android.control.aeCompensationStep and do the sanity check.
+     * Get value of key android.control.aeCompensationStep and do the validation check.
      *
      * @return default value if the value is null.
      */
@@ -1605,7 +1605,7 @@
     }
 
     /**
-     * Get value of key android.control.aeCompensationRange and do the sanity check.
+     * Get value of key android.control.aeCompensationRange and do the validation check.
      *
      * @return default value if the value is null or malformed.
      */
@@ -1635,7 +1635,7 @@
     }
 
     /**
-     * Get availableVideoStabilizationModes and do the sanity check.
+     * Get availableVideoStabilizationModes and do the validation check.
      *
      * @return available video stabilization modes, empty array if it is unavailable.
      */
@@ -1666,7 +1666,7 @@
     }
 
     /**
-     * Get availableOpticalStabilization and do the sanity check.
+     * Get availableOpticalStabilization and do the validation check.
      *
      * @return available optical stabilization modes, empty array if it is unavailable.
      */
@@ -1780,7 +1780,7 @@
     }
 
     /**
-     * Get max pipeline depth and do the sanity check.
+     * Get max pipeline depth and do the validation check.
      *
      * @return max pipeline depth, default value if it is not available.
      */
@@ -1846,7 +1846,7 @@
 
 
     /**
-     * Get available capabilities and do the sanity check.
+     * Get available capabilities and do the validation check.
      *
      * @return reported available capabilities list, empty list if the value is unavailable.
      */
@@ -2070,7 +2070,7 @@
     }
 
     /**
-     * Get max number of output raw streams and do the basic sanity check.
+     * Get max number of output raw streams and do the basic validation check.
      *
      * @return reported max number of raw output stream
      */
@@ -2083,7 +2083,7 @@
     }
 
     /**
-     * Get max number of output processed streams and do the basic sanity check.
+     * Get max number of output processed streams and do the basic validation check.
      *
      * @return reported max number of processed output stream
      */
@@ -2096,7 +2096,7 @@
     }
 
     /**
-     * Get max number of output stalling processed streams and do the basic sanity check.
+     * Get max number of output stalling processed streams and do the basic validation check.
      *
      * @return reported max number of stalling processed output stream
      */
@@ -2109,7 +2109,7 @@
     }
 
     /**
-     * Get lens facing and do the sanity check
+     * Get lens facing and do the validation check
      * @return lens facing, return default value (BACK) if value is unavailable.
      */
     public int getLensFacingChecked() {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java
index 31b7967..47caf0a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java
@@ -309,7 +309,7 @@
     private void changeExposure(CaptureRequest.Builder requestBuilder,
             long expTime, int sensitivity) {
         // Check if the max analog sensitivity is available and no larger than max sensitivity.
-        // The max analog sensitivity is not actually used here. This is only an extra sanity check.
+        // The max analog sensitivity is not actually used here. This is only an extra check.
         mStaticInfo.getMaxAnalogSensitivityChecked();
 
         expTime = mStaticInfo.getExposureClampToRange(expTime);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
index 6a4db57..dc8da48 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
@@ -985,7 +985,7 @@
     }
 
     /**
-     * Validate video snapshot capture image object sanity and test.
+     * Validate video snapshot capture image object soundness and test.
      *
      * <p> Check for size, format and jpeg decoding</p>
      *
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
index f7373f7..cbdcc36 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
@@ -570,7 +570,7 @@
     }
 
     /**
-     * Validate JPEG capture image object sanity and test.
+     * Validate JPEG capture image object soundness and test.
      * <p>
      * In addition to image object sanity, this function also does the decoding
      * test, which is slower.
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 5aaca43..70ef69d 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11900,6 +11900,7 @@
     field public static final int INVALID_ID = -1; // 0xffffffff
     field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
     field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
+    field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
     field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
     field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
   }
@@ -24189,6 +24190,7 @@
     method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
     method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
     method public int getAllowedCapturePolicy();
+    method public int getAudioHwSyncForSession(int);
     method public android.media.AudioDeviceInfo[] getDevices(int);
     method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
     method public int getMode();
@@ -46014,6 +46016,7 @@
     method @Nullable public android.net.LinkProperties getLinkProperties();
     method public int getNetworkType();
     method public int getState();
+    method public int getTransportType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR;
   }
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 45ff6d3..3c0b955 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -31,6 +31,14 @@
 
 }
 
+package android.media {
+
+  public class AudioManager {
+    field public static final int FLAG_FROM_KEY = 4096; // 0x1000
+  }
+
+}
+
 package android.os {
 
   public class Binder implements android.os.IBinder {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 222e563..844e929 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -4141,6 +4141,7 @@
     method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
     method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4159,6 +4160,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
     method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4169,6 +4171,11 @@
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
     field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
+    field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+    field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+    field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+    field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+    field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
     field public static final int SUCCESS = 0; // 0x0
   }
@@ -9706,6 +9713,7 @@
     method @Deprecated public int getDataConnectionApnTypeBitMask();
     method @Deprecated public int getDataConnectionFailCause();
     method @Deprecated public int getDataConnectionState();
+    method public int getId();
   }
 
   public final class PreciseDisconnectCause {
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 995a3ec..f4e704e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -38,6 +38,8 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.doze.DozeHost;
+import com.android.systemui.pip.phone.PipMenuActivity;
+import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
@@ -142,6 +144,13 @@
                 mainHandler, transactionPool).build();
     }
 
+    @Singleton
+    @PipMenuActivityClass
+    @Provides
+    static Class<?> providePipMenuActivityClass() {
+        return PipMenuActivity.class;
+    }
+
     @Binds
     abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
index aea6914..7db2823 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
@@ -16,12 +16,12 @@
 
 package com.android.systemui.car.userswitcher;
 
-import android.app.ActivityManager;
 import android.car.Car;
 import android.car.user.CarUserManager;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.car.window.OverlayViewMediator;
 
@@ -36,13 +36,16 @@
     private static final String TAG = "UserSwitchTransitionViewMediator";
 
     private final CarServiceProvider mCarServiceProvider;
+    private final CarDeviceProvisionedController mCarDeviceProvisionedController;
     private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
 
     @Inject
     public UserSwitchTransitionViewMediator(
             CarServiceProvider carServiceProvider,
+            CarDeviceProvisionedController carDeviceProvisionedController,
             UserSwitchTransitionViewController userSwitchTransitionViewController) {
         mCarServiceProvider = carServiceProvider;
+        mCarDeviceProvisionedController = carDeviceProvisionedController;
         mUserSwitchTransitionViewController = userSwitchTransitionViewController;
     }
 
@@ -74,7 +77,7 @@
     @VisibleForTesting
     void handleUserLifecycleEvent(CarUserManager.UserLifecycleEvent event) {
         if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING
-                && ActivityManager.getCurrentUser() == event.getUserId()) {
+                && mCarDeviceProvisionedController.getCurrentUser() == event.getUserId()) {
             mUserSwitchTransitionViewController.handleShow(event.getUserId());
         }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
index 5f9665f..0452b83 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
@@ -172,32 +172,32 @@
     private static class Filter {
         private static final String ALL = "*";
 
-        private final ArraySet<String> mWhitelist;
-        private final ArraySet<String> mBlacklist;
+        private final ArraySet<String> mToInclude;
+        private final ArraySet<String> mToExclude;
 
-        private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
-            mWhitelist = whitelist;
-            mBlacklist = blacklist;
+        private Filter(ArraySet<String> toInclude, ArraySet<String> toExclude) {
+            mToInclude = toInclude;
+            mToExclude = toExclude;
         }
 
         boolean matches(String packageName) {
             if (packageName == null) return false;
-            if (onBlacklist(packageName)) return false;
-            return onWhitelist(packageName);
+            if (toExclude(packageName)) return false;
+            return toInclude(packageName);
         }
 
-        private boolean onBlacklist(String packageName) {
-            return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+        private boolean toExclude(String packageName) {
+            return mToExclude.contains(packageName) || mToExclude.contains(ALL);
         }
 
-        private boolean onWhitelist(String packageName) {
-            return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+        private boolean toInclude(String packageName) {
+            return mToInclude.contains(ALL) || mToInclude.contains(packageName);
         }
 
         void dump(PrintWriter pw) {
             pw.print("Filter[");
-            dump("whitelist", mWhitelist, pw); pw.print(',');
-            dump("blacklist", mBlacklist, pw); pw.print(']');
+            dump("toInclude", mToInclude, pw); pw.print(',');
+            dump("toExclude", mToExclude, pw); pw.print(']');
         }
 
         private void dump(String name, ArraySet<String> set, PrintWriter pw) {
@@ -221,18 +221,18 @@
         // e.g. "com.package1", or "com.android.systemui, com.android.keyguard" or "*"
         static Filter parse(String value) {
             if (value == null) return null;
-            ArraySet<String> whitelist = new ArraySet<String>();
-            ArraySet<String> blacklist = new ArraySet<String>();
+            ArraySet<String> toInclude = new ArraySet<String>();
+            ArraySet<String> toExclude = new ArraySet<String>();
             for (String token : value.split(",")) {
                 token = token.trim();
                 if (token.startsWith("-") && token.length() > 1) {
                     token = token.substring(1);
-                    blacklist.add(token);
+                    toExclude.add(token);
                 } else {
-                    whitelist.add(token);
+                    toInclude.add(token);
                 }
             }
-            return new Filter(whitelist, blacklist);
+            return new Filter(toInclude, toExclude);
         }
     }
 
diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index d769cac..86b86d4 100644
--- a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -63,7 +63,7 @@
 
     private static final String TAG = "AAA++VerifyTest";
 
-    private static final Class[] BASE_CLS_WHITELIST = {
+    private static final Class[] BASE_CLS_TO_INCLUDE = {
             SysuiTestCase.class,
             SysuiBaseFragmentTest.class,
     };
@@ -85,7 +85,7 @@
             if (!isTestClass(cls)) continue;
 
             boolean hasParent = false;
-            for (Class<?> parent : BASE_CLS_WHITELIST) {
+            for (Class<?> parent : BASE_CLS_TO_INCLUDE) {
                 if (parent.isAssignableFrom(cls)) {
                     hasParent = true;
                     break;
@@ -129,7 +129,7 @@
     }
 
     private String getClsStr() {
-        return TextUtils.join(",", Arrays.asList(BASE_CLS_WHITELIST)
+        return TextUtils.join(",", Arrays.asList(BASE_CLS_TO_INCLUDE)
                 .stream().map(cls -> cls.getSimpleName()).toArray());
     }
 
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
index 20576e9..67f222b 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
@@ -220,7 +220,7 @@
 
         verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
         verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display1);
-        verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display2);
+        verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2);
         verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display3);
         verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display1);
         verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
index de6feb6..7aeffce 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.car.userswitcher;
 
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -24,6 +25,8 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.car.CarSystemUiTest;
 
@@ -37,13 +40,15 @@
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
-public class UserSwitchTransitionViewMediatorTest {
+public class UserSwitchTransitionViewMediatorTest extends SysuiTestCase {
     private static final int TEST_USER = 100;
 
     private UserSwitchTransitionViewMediator mUserSwitchTransitionViewMediator;
     @Mock
     private CarServiceProvider mCarServiceProvider;
     @Mock
+    private CarDeviceProvisionedController mCarDeviceProvisionedController;
+    @Mock
     private UserSwitchTransitionViewController mUserSwitchTransitionViewController;
     @Mock
     private CarUserManager.UserLifecycleEvent mUserLifecycleEvent;
@@ -53,21 +58,35 @@
         MockitoAnnotations.initMocks(this);
 
         mUserSwitchTransitionViewMediator = new UserSwitchTransitionViewMediator(
-                mCarServiceProvider, mUserSwitchTransitionViewController);
-
+                mCarServiceProvider, mCarDeviceProvisionedController,
+                mUserSwitchTransitionViewController);
+        when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER);
     }
 
     @Test
-    public void onUserLifecycleEvent_userStarting_callsHandleShow() {
+    public void onUserLifecycleEvent_userStarting_isCurrentUser_callsHandleShow() {
         when(mUserLifecycleEvent.getEventType()).thenReturn(
                 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
         when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER);
+
         mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
 
         verify(mUserSwitchTransitionViewController).handleShow(TEST_USER);
     }
 
     @Test
+    public void onUserLifecycleEvent_userStarting_isNotCurrentUser_doesNotCallHandleShow() {
+        when(mUserLifecycleEvent.getEventType()).thenReturn(
+                CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
+        when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER);
+        when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER + 1);
+
+        mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
+
+        verify(mUserSwitchTransitionViewController, never()).handleShow(TEST_USER);
+    }
+
+    @Test
     public void onUserLifecycleEvent_userSwitching_callsHandleHide() {
         when(mUserLifecycleEvent.getEventType()).thenReturn(
                 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
index 31f1170..f77294e 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
@@ -19,6 +19,8 @@
 import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.INVALID_VALUE;
 import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.VOICE_RECOGNITION_STARTED;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -40,11 +42,13 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 @CarSystemUiTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
+// TODO(b/162866441): Refactor to use the Executor pattern instead.
 public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
 
     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
@@ -52,13 +56,15 @@
 
     private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier;
     private TestableLooper mTestableLooper;
+    private Handler mHandler;
     private Handler mTestHandler;
     private BluetoothDevice mBluetoothDevice;
 
     @Before
     public void setUp() throws Exception {
         mTestableLooper = TestableLooper.get(this);
-        mTestHandler = spy(new Handler(mTestableLooper.getLooper()));
+        mHandler = new Handler(mTestableLooper.getLooper());
+        mTestHandler = spy(mHandler);
         mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
                 BLUETOOTH_REMOTE_ADDRESS);
         mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier(
@@ -74,8 +80,14 @@
 
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
-        verify(mTestHandler).post(any());
+        mHandler.post(() -> {
+            ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
+            verify(mTestHandler).post(argumentCaptor.capture());
+            assertThat(argumentCaptor.getValue()).isNotNull();
+            assertThat(argumentCaptor.getValue()).isNotEqualTo(this);
+        });
     }
 
     @Test
@@ -86,8 +98,11 @@
 
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
-        verify(mTestHandler, never()).post(any());
+        mHandler.post(() -> {
+            verify(mTestHandler, never()).post(any());
+        });
     }
 
     @Test
@@ -97,8 +112,11 @@
 
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
-        verify(mTestHandler, never()).post(any());
+        mHandler.post(() -> {
+            verify(mTestHandler, never()).post(any());
+        });
     }
 
     @Test
@@ -108,7 +126,10 @@
 
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
-        verify(mTestHandler, never()).post(any());
+        mHandler.post(() -> {
+            verify(mTestHandler, never()).post(any());
+        });
     }
 }
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index bcaee36..f108e06 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -259,18 +259,19 @@
     private void onDeviceFound(@Nullable DeviceFilterPair device) {
         if (device == null) return;
 
-        if (mDevicesFound.contains(device)) {
-            return;
-        }
-
-        if (DEBUG) Log.i(LOG_TAG, "Found device " + device);
-
         Handler.getMain().sendMessage(obtainMessage(
                 DeviceDiscoveryService::onDeviceFoundMainThread, this, device));
     }
 
     @MainThread
     void onDeviceFoundMainThread(@NonNull DeviceFilterPair device) {
+        if (mDevicesFound.contains(device)) {
+            Log.i(LOG_TAG, "Skipping device " + device + " - already among found devices");
+            return;
+        }
+
+        Log.i(LOG_TAG, "Found device " + device);
+
         if (mDevicesFound.isEmpty()) {
             onReadyToShowUI();
         }
@@ -428,10 +429,10 @@
 
         @Override
         public String toString() {
-            return "DeviceFilterPair{" +
-                    "device=" + device +
-                    ", filter=" + filter +
-                    '}';
+            return "DeviceFilterPair{"
+                    + "device=" + device + " " + getDisplayName()
+                    + ", filter=" + filter
+                    + '}';
         }
     }
 
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
index 276d55ee..9fe7ab65 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
@@ -26,7 +26,7 @@
 import android.view.View;
 
 /**
- * Dummy view to emulate stuff an OEM may want to do.
+ * Fake view to emulate stuff an OEM may want to do.
  */
 public class FakeView extends View {
     static final long TICK_DELAY = 30*1000; // 30 seconds
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 704d264..6751fa4 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Wys Bluetooth-toestelle sonder name"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Deaktiveer absolute volume"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktiveer Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbeterde konnektiwiteit"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-weergawe"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Kies Bluetooth AVRCP-weergawe"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-weergawe"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 585924d..470e780 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"የብሉቱዝ መሣሪያዎችን ያለ ስሞች አሳይ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ፍጹማዊ ድምፅን አሰናክል"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheን አንቃ"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"የተሻሻለ ተገናኝነት"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"የብሉቱዝ AVRCP ስሪት"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"የብሉቱዝ AVRCP ስሪት ይምረጡ"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"የብሉቱዝ MAP ስሪት"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 39777cd..9acfa0d 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -152,7 +152,7 @@
     <string name="user_guest" msgid="6939192779649870792">"ضيف"</string>
     <string name="unknown" msgid="3544487229740637809">"غير معروف"</string>
     <string name="running_process_item_user_label" msgid="3988506293099805796">"المستخدم: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
-    <string name="launch_defaults_some" msgid="3631650616557252926">"تم تعيين بعض الإعدادات التلقائية"</string>
+    <string name="launch_defaults_some" msgid="3631650616557252926">"تم ضبط بعض الإعدادات التلقائية"</string>
     <string name="launch_defaults_none" msgid="8049374306261262709">"لم يتم تعيين إعدادات تلقائية"</string>
     <string name="tts_settings" msgid="8130616705989351312">"إعدادات تحويل النص إلى كلام"</string>
     <string name="tts_settings_title" msgid="7602210956640483039">"تحويل النص إلى كلام"</string>
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"عرض أجهزة البلوتوث بدون أسماء"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"إيقاف مستوى الصوت المطلق"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏تفعيل Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"إمكانية اتصال محسّن"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏إصدار Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏اختيار إصدار Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏إصدار Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e0455cb..f993dba 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"পূৰ্ণ মাত্ৰাৰ ভলিউম অক্ষম কৰক"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche সক্ষম কৰক"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"উন্নত সংযোগ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ব্লুটুথ AVRCP সংস্কৰণ"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ব্লুটুথ AVRCP সংস্কৰণ বাছনি কৰক"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ব্লুটুথ MAP সংস্কৰণ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 6565d53..6a50661 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth cihazlarını adsız göstərin"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Mütləq səs həcmi deaktiv edin"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche\'ni aktiv edin"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Təkmilləşdirilmiş Bağlantı"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP Versiya"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP Versiyasını seçin"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP Versiyası"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3ced29b..cf988ab 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući glavno podešavanje jačine zvuka"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšano povezivanje"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzija Bluetooth AVRCP-a"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izaberite verziju Bluetooth AVRCP-a"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzija Bluetooth MAP-a"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 01d7682..8f71509 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Паказваць прылады Bluetooth без назваў"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Адключыць абсалютны гук"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Уключыць Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Палепшанае падключэнне"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версія Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Выбраць версію Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версія Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index d042c0f..747cb26 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показване на устройствата с Bluetooth без имена"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Деактивиране на пълната сила на звука"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Активиране на Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Подобрена свързаност"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версия на AVRCP за Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Избиране на версия на AVRCP за Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP версия за Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 2db23f7..87f3b7a 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখুন"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"চূড়ান্ত ভলিউম অক্ষম করুন"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ফিচার চালু করুন"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"কানেক্টিভিটি উন্নত করা হয়েছে"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ব্লুটুথ AVRCP ভার্সন"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ব্লুটুথ AVRCP ভার্সন বেছে নিন"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ব্লুটুথ MAP ভার্সন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f26fe9d..e329c99 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući apsolutnu jačinu zvuka"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšana povezivost"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP verzija"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Odaberite Bluetooth AVRCP verziju"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP verzija"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 3ca9d52..5ffdacd 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra els dispositius Bluetooth sense el nom"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desactiva el volum absolut"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activa Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivitat millorada"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versió AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versió AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versió MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a5532e0..0aef99f 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovat zařízení Bluetooth bez názvů"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zakázat absolutní hlasitost"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Zapnout funkci Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Lepší připojování"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verze profilu Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Vyberte verzi profilu Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verze MAP pro Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 8ca22d7..98068cb 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheder uden navne"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Deaktiver absolut lydstyrke"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivér Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced Connectivity"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"AVRCP-version for Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Vælg AVRCP-version for Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-version for Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 6b0ae2e2..0837ad3 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-Geräte ohne Namen anzeigen"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Absolute Lautstärkeregelung deaktivieren"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Bluetooth-Gabeldorsche aktivieren"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbesserte Konnektivität"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-Version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP-Version auswählen"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-Version"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 4d7c882..1f9d977 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Εμφάνιση συσκευών Bluetooth χωρίς ονόματα"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Απενεργοποίηση απόλυτης έντασης"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ενεργοποίηση Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Βελτιωμένη συνδεσιμότητα"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Έκδοση AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Επιλογή έκδοσης AVRCP Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Έκδοση MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index cc3b2aa..abe61a9 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index a9f039a..959ad46 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index cc3b2aa..abe61a9 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index cc3b2aa..abe61a9 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 41c20e0..738dd2a 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎Show Bluetooth devices without names‎‏‎‎‏‎"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‎Disable absolute volume‎‏‎‎‏‎"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎Enable Gabeldorsche‎‏‎‎‏‎"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎Enhanced Connectivity‎‏‎‎‏‎"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎Bluetooth AVRCP Version‎‏‎‎‏‎"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎Select Bluetooth AVRCP Version‎‏‎‎‏‎"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‎Bluetooth MAP Version‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 287a1ac..d1e4fb5 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inhabilitar volumen absoluto"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Habilitar Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividad mejorada"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión de AVRCP del Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión de AVRCP del Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 9d34557..9ad71e2 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inhabilitar volumen absoluto"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Habilitar Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividad mejorada"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión AVRCP de Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index d003ef0..14d3b57 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Kuva ilma nimedeta Bluetoothi seadmed"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Keela absoluutne helitugevus"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Luba Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Täiustatud ühenduvus"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetoothi AVRCP versioon"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Valige Bluetoothi AVRCP versioon"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetoothi MAP-i versioon"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 0042321..dcdadbd 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth bidezko gailuak izenik gabe"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desgaitu bolumen absolutua"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gaitu Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Konexio hobeak"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP bertsioa"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Hautatu Bluetooth AVRCP bertsioa"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAParen bertsioa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1c08815..f3b22d3 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"نمایش دستگاه‌های بلوتوث بدون نام"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"غیرفعال کردن میزان صدای مطلق"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏فعال کردن Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"اتصال بهبودیافته"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏نسخه AVRCP بلوتوث"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏انتخاب نسخه AVRCP بلوتوث"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏نسخه MAP بلوتوث"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 3945e55..3d28f1d 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Näytä nimettömät Bluetooth-laitteet"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Poista yleinen äänenvoimakkuuden säätö käytöstä"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ota Gabeldorsche käyttöön"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Parannetut yhteydet"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetoothin AVRCP-versio"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Valitse Bluetoothin AVRCP-versio"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetoothin MAP-versio"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 140d4ce..87d3de1 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Désactiver le volume absolu"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activer le Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivité améliorée"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Version du profil Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Sélectionner la version du profil Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Version du profil Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 1b1ae8e..ddf2bc0 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -251,13 +251,12 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certification affichage sans fil"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser l\'enregistrement d\'infos Wi-Fi détaillées"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche Wi‑Fi"</string>
-    <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC sur Wi-Fi"</string>
+    <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC en Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Données mobiles toujours actives"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Désactiver le volume absolu"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activer Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivité améliorée"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Version Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Sélectionner la version Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Version Bluetooth MAP"</string>
@@ -284,7 +283,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string>
-    <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse e-mail MAC de cet appareil peut changer lors de chaque connexion à un réseau pour lequel le changement aléatoire d\'adresse MAC est activé."</string>
+    <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil peut changer lors de chaque connexion à un réseau Wi-Fi pour lequel le changement aléatoire d\'adresse MAC est activé"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index f9d57c4..af43099 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sen nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desactivar volume absoluto"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activar Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade mellorada"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión de Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona a versión de Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index aa1f960..3261f69 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"નામ વિનાના બ્લૂટૂથ ઉપકરણો બતાવો"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ચાલુ કરો"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"વિસ્તૃત કનેક્ટિવિટી"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"બ્લૂટૂથ AVRCP સંસ્કરણ"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"બ્લૂટૂથ AVRCP સંસ્કરણ પસંદ કરો"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"બ્લૂટૂથ MAP વર્ઝન"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9b6a27a..904a70e 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ब्लूटूथ से आवाज़ के नियंत्रण की सुविधा रोकें"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche चालू करें"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"कनेक्टिविटी बेहतर बनाएं"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ एवीआरसीपी वर्शन"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP वर्शन चुनें"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लूटूथ का MAP वर्शन"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 14e3330..3edc452 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući apsolutnu glasnoću"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšana povezivost"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzija AVRCP-a za Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Odaberite verziju AVRCP-a za Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzija MAP-a za Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index d16ff03..fec2dd6 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Név nélküli Bluetooth-eszközök megjelenítése"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Abszolút hangerő funkció letiltása"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"A Gabeldorsche engedélyezése"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced Connectivity"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"A Bluetooth AVRCP-verziója"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"A Bluetooth AVRCP-verziójának kiválasztása"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"A Bluetooth MAP-verziója"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b010b50..f219d24 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ցուցադրել Bluetooth սարքերն առանց անունների"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Անջատել ձայնի բացարձակ ուժգնությունը"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Միացնել Gabeldorsche-ը"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Տվյալների լավացված փոխանակում"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP տարբերակը"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Ընտրել Bluetooth AVRCP տարբերակը"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-ի տարբերակ"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 37cf189f..3ab50cc 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -31,7 +31,7 @@
     <item msgid="7852381437933824454">"Memutus sambungan..."</item>
     <item msgid="5046795712175415059">"Sambungan terputus"</item>
     <item msgid="2473654476624070462">"Gagal"</item>
-    <item msgid="9146847076036105115">"Dicekal"</item>
+    <item msgid="9146847076036105115">"Diblokir"</item>
     <item msgid="4543924085816294893">"Menghindari sambungan buruk untuk sementara"</item>
   </string-array>
   <string-array name="wifi_status_with_ssid">
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 42ccd53..a6f8846 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -180,8 +180,8 @@
     <string name="tts_engine_settings_button" msgid="477155276199968948">"Luncurkan setelan mesin"</string>
     <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"Mesin yang dipilih"</string>
     <string name="tts_general_section_title" msgid="8919671529502364567">"Umum"</string>
-    <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Setel ulang tinggi nada ucapan"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Setel ulang tinggi nada diucapkannya teks menjadi default."</string>
+    <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Reset tinggi nada ucapan"</string>
+    <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Reset tinggi nada diucapkannya teks menjadi default."</string>
   <string-array name="tts_rate_entries">
     <item msgid="9004239613505400644">"Sangat lambat"</item>
     <item msgid="1815382991399815061">"Lambat"</item>
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tampilkan perangkat Bluetooth tanpa nama"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Nonaktifkan volume absolut"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktifkan Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Konektivitas Yang Disempurnakan"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pilih Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versi MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 0ebc341..caf2323 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Sýna Bluetooth-tæki án heita"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Slökkva á samstillingu hljóðstyrks"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Virkja Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Aukin tengigeta"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-útgáfa"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Velja Bluetooth AVRCP-útgáfu"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-útgáfa"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 50fdfc9..8d18727 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra dispositivi Bluetooth senza nome"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disattiva volume assoluto"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Attiva Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Connettività migliorata"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versione Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Seleziona versione Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versione Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fb7d00f..fff881c 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"‏הצגת מכשירי Bluetooth ללא שמות"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"השבת עוצמת קול מוחלטת"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏הפעלת Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"קישוריות משופרת"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏Bluetooth גרסה AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏בחר Bluetooth גרסה AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏גרסת Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 3537cea..5e579b7 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth デバイスを名前なしで表示"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"絶対音量を無効にする"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche を有効にする"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"接続強化"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP バージョン"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP バージョンを選択する"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP バージョン"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 9b671a8..1b5fae9 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-მოწყობილობების ჩვენება სახელების გარეშე"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ხმის აბსოლუტური სიძლიერის გათიშვა"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche-ის ჩართვა"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"კავშირის გაძლიერებული შესაძლებლობა"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth-ის AVRCP-ის ვერსია"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"აირჩიეთ Bluetooth-ის AVRCP-ის ვერსია"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-ის ვერსია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 279aca0..9c290e9 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth құрылғыларын атаусыз көрсету"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Абсолютті дыбыс деңгейін өшіру"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche функциясын іске қосу"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Жетілдірілген байланыс"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP нұсқасы"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP нұсқасын таңдау"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP нұсқасы"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 03065e8..2878db1 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"បង្ហាញ​ឧបករណ៍​ប្ល៊ូធូស​គ្មានឈ្មោះ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"បិទកម្រិតសំឡេងលឺខ្លាំង"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"បើក Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"ការតភ្ជាប់​ដែលបានធ្វើឱ្យប្រសើរឡើង"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"កំណែប្ល៊ូធូស AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ជ្រើសរើសកំណែប្ល៊ូធូស AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"កំណែ​ប៊្លូធូស MAP"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 71c5e49..7b01056 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ಹೆಸರುಗಳಿಲ್ಲದ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"ವರ್ಧಿತ ಸಂಪರ್ಕ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿ"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿಯನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ಬ್ಲೂಟೂತ್ MAP ಆವೃತ್ತಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 5d82eae..696ed29 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"이름이 없는 블루투스 기기 표시"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"절대 볼륨 사용 안함"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche 사용 설정"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"향상된 연결"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"블루투스 AVRCP 버전"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"블루투스 AVRCP 버전 선택"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"블루투스 MAP 버전"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 2702392..c4b5f7e 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Аталышсыз Bluetooth түзмөктөрү көрсөтүлсүн"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Үндүн абсолюттук деңгээли өчүрүлсүн"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche функциясын иштетүү"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Жакшыртылган туташуу"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP версиясы"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP версиясын тандоо"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP версиясы"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 7a2c338..a72861e 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"ເປີດໃຊ້ Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"ການເຊື່ອມຕໍ່ທີ່ເສີມແຕ່ງແລ້ວ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ເວີຊັນ Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ເລືອກເວີຊັນ Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ເວີຊັນ Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index b73aa66..c72bf21 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rodyti „Bluetooth“ įrenginius be pavadinimų"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Išjungti didžiausią garsą"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Įgalinti „Gabeldorsche“"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Patobulintas ryšys"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"„Bluetooth“ AVRCP versija"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pasirinkite „Bluetooth“ AVRCP versiją"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"„Bluetooth“ MRK versija"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 8e5d24c..d95e57d 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rādīt Bluetooth ierīces bez nosaukumiem"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Atspējot absolūto skaļumu"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Iespējot Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Uzlabota savienojamība"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP versija"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Atlasiet Bluetooth AVRCP versiju"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP versija"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 34299d8..fb7b634 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажувај уреди со Bluetooth без имиња"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Оневозможете апсолутна јачина на звук"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Овозможи Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Подобрена поврзливост"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Верзија Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Изберете верзија Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Верзија на Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index c95f8bf..3c281c8 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ കാണിക്കുക"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"അബ്‌സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche പ്രവർത്തനക്ഷമമാക്കുക"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"മെച്ചപ്പെടുത്തിയ കണക്റ്റിവിറ്റി"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP പതിപ്പ്"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP പതിപ്പ് തിരഞ്ഞെടുക്കുക"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP പതിപ്പ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 8407db6..37fc5b4 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Нэргүй Bluetooth төхөөрөмжийг харуулах"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche-г идэвхжүүлэх"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Сайжруулсан холболт"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP хувилбар"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP хувилбарыг сонгох"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP хувилбар"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index c50f365..360f158 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नावांशिवाय ब्‍लूटूथ डिव्‍हाइस दाखवा"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"संपूर्ण आवाज बंद करा"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"गाबलडॉर्ष सुरू करा"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"वर्धित कनेक्टिव्हिटी"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ AVRCP आवृत्ती"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP आवृत्ती निवडा"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लूटूथ MAP आवृत्ती"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index a0a434f..68356df2 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tunjukkan peranti Bluetooth tanpa nama"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Lumpuhkan kelantangan mutlak"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Dayakan Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Kesambungan Dipertingkat"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pilih Versi AVRCP Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versi MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index fa49929..3729a83 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"အမည်မရှိသော ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသရန်"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ကို ဖွင့်ရန်"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"အရည်အသွေးမြှင့်တင်ထားသော ချိတ်ဆက်နိုင်မှု"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ဘလူးတုသ် AVRCP ဗားရှင်း"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ဘလူးတုသ် AVRCP ဗားရှင်းကို ရွေးပါ"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ဘလူးတုသ် MAP ဗားရှင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index aeaba31..0e0e761 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheter uten navn"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Slå av funksjonen for absolutt volum"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktiver Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Forbedret tilkobling"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-versjon"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Velg Bluetooth AVRCP-versjon"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-versjon"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 4a2c171..762d830 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नामकरण नगरिएका ब्लुटुथ यन्त्रहरू देखाउनुहोस्"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche सक्षम पार्नुहोस्"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"परिष्कृत जडान"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लुटुथको AVRCP संस्करण"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लुटुथको AVRCP संस्करण चयन गर्नुहोस्"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लुटुथको MAP संस्करण"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 32cc39e..83b72e9 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder namen weergeven"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Absoluut volume uitschakelen"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche inschakelen"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbeterde connectiviteit"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth-AVRCP-versie"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth-AVRCP-versie selecteren"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-versie voor bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 8e5bf25..d200f50 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ବ୍ଲୁଟୂଥ୍‍‌ ଡିଭାଇସ୍‌ଗୁଡ଼ିକୁ ନାମ ବିନା ଦେଖନ୍ତୁ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ପୂର୍ଣ୍ଣ ଭଲ୍ୟୁମ୍‌ ଅକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"ଗାବେଲ୍‌ଡୋର୍ସ ସକ୍ରିୟ କରନ୍ତୁ"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"ଏନହାନ୍ସଡ୍ କନେକ୍ଟିଭିଟି"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ବ୍ଲୁଟୂଥ୍‌ AVRCP ଭର୍ସନ୍"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ବ୍ଲୁଟୂଥ୍‍‌ AVRCP ଭର୍ସନ୍‌"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ବ୍ଲୁଟୁଥ୍ MAP ସଂସ୍କରଣ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 1570013..354ee12 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ਪੂਰਨ ਅਵਾਜ਼ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"ਵਿਸਤ੍ਰਿਤ ਕਨੈਕਟੀਵਿਟੀ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ ਚੁਣੋ"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP ਵਰਜਨ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 1120c50..095412c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Pokaż urządzenia Bluetooth bez nazw"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Wyłącz głośność bezwzględną"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Włącz Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Lepsza obsługa połączeń"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Wersja AVRCP Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Wybierz wersję AVRCP Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Wersja MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 4214a27..895a987 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade melhorada"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 508cbfc..2d9f037 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar o Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Conetividade melhorada"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão de Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão de Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão do MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 4214a27..895a987 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade melhorada"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão do Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 663d3f7..728db17 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afișați dispozitivele Bluetooth fără nume"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Dezactivați volumul absolut"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activați Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectivitate îmbunătățită"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versiunea AVRCP pentru Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selectați versiunea AVRCP pentru Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versiunea MAP pentru Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 9c0a2f5..ff2115e 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показывать Bluetooth-устройства без названий"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Отключить абсолютный уровень громкости"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Включить Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Улучшенный обмен данными"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версия Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Выберите версию Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версия Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 8d0e93e..a883cc6 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"නම් නොමැති බ්ලූටූත් උපාංග පෙන්වන්න"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche සබල කරන්න"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"වැඩිදියුණු කළ සබැඳුම් හැකියාව"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"බ්ලූටූත් AVRCP අනුවාදය"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"බ්ලූටූත් AVRCP අනුවාදය තෝරන්න"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP අනුවාදය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index f39a741..05c6379 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovať zariadenia Bluetooth bez názvov"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zakázať absolútnu hlasitosť"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Povoliť Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Zlepšené možnosti pripojenia"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzia rozhrania Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Zvoľte verziu rozhrania Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzia profilu Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 233c8e4..fd216e8 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogočanje absolutne glasnosti"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogoči Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Izboljšana povezljivost"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Različica profila AVRCP za Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izberite različico profila AVRCP za Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Različica profila MAP za Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 6af1062..002c7fc 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Shfaq pajisjet me Bluetooth pa emra"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Çaktivizo volumin absolut"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivizo Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Lidhshmëria e përmirësuar"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versioni AVRCP i Bluetooth-it"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Zgjidh versionin AVRCP të Bluetooth-it"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versioni MAP i Bluetooth-it"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 74c2aec..25a1beb7 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажи Bluetooth уређаје без назива"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Онемогући главно подешавање јачине звука"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Омогући Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Побољшано повезивање"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Верзија Bluetooth AVRCP-а"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Изаберите верзију Bluetooth AVRCP-а"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Верзија Bluetooth MAP-а"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index fe1b0a8..352cb0a 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Visa namnlösa Bluetooth-enheter"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inaktivera Absolute volume"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivera Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Förbättrad anslutning"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"AVRCP-version för Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Välj AVRCP-version för Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-version för Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 5c80627..d2891a0 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Onyesha vifaa vya Bluetooth visivyo na majina"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zima sauti kamili"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Washa Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Muunganisho Ulioboreshwa"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Toleo la Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Chagua Toleo la Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Toleo la Ramani ya Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 241644f..7837dd8 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheவை இயக்கு"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"மேம்படுத்தப்பட்ட இணைப்புநிலை"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"புளூடூத் AVRCP பதிப்பு"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"புளூடூத் AVRCP பதிப்பைத் தேர்ந்தெடு"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"புளூடூத்தின் MAP பதிப்பு"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a9ec2ea9..60001a0 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"పేర్లు లేని బ్లూటూత్ పరికరాలు  చూపించు"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"సంపూర్ణ వాల్యూమ్‌‍ను నిలిపివేయి"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheను ఎనేబుల్ చేయి"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"మెరుగైన కనెక్టివిటీ"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"బ్లూటూత్ AVRCP వెర్షన్"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"బ్లూటూత్ AVRCP సంస్కరణను ఎంచుకోండి"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"బ్లూటూత్ MAP వెర్షన్‌"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index b8343c6..defc33e 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"แสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"เปิดใช้ Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"การเชื่อมต่อที่ปรับปรุงแล้ว"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"เวอร์ชันของบลูทูธ AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"เลือกเวอร์ชันของบลูทูธ AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"เวอร์ชัน MAP ของบลูทูธ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 8aeb392..5d4e975 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ipakita ang mga Bluetooth device na walang pangalan"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"I-disable ang absolute volume"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"I-enable ang Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Pinagandang Pagkakonekta"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bersyon ng AVRCP ng Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pumili ng Bersyon ng AVRCP ng Bluetooth"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bersyon ng MAP ng Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index e6d9380..f01f3fa 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Adsız Bluetooth cihazlarını göster"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Mutlak sesi iptal et"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche\'yi etkileştir"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Gelişmiş Bağlantı"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP Sürümü"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP Sürümünü seçin"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP Sürümü"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cf1fafd..9ca2f06 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показувати пристрої Bluetooth без назв"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Вимкнути абсолютну гучність"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Увімкнути Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Покращене з\'єднання"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версія Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Виберіть версію Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версія Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index b7fbe6f..8953f50 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"مطلق والیوم کو غیر فعال کریں"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏Gabeldorsche فعال کریں"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"بہتر کردہ کنیکٹوٹی"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏بلوٹوتھ AVRCP ورژن"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏بلوٹوتھ AVRCP ورژن منتخب کریں"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏بلوٹوتھ MAP ورژن"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f81731a..f25b3ac 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth qurilmalarini nomlarisiz ko‘rsatish"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Tovush balandligining mutlaq darajasini faolsizlantirish"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche funksiyasini yoqish"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Kuchaytirilgan aloqa"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP versiyasi"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP versiyasini tanlang"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP versiyasi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index b7ccf8d..b5798f3 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Hiển thị các thiết bị Bluetooth không có tên"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Vô hiệu hóa âm lượng tuyệt đối"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Bật tính năng Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Kết nối nâng cao"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Phiên bản Bluetooth AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Chọn phiên bản Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Phiên bản Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 75c1333..c4dcfff 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"显示没有名称的蓝牙设备"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用绝对音量功能"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"启用“Gabeldorsche”"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"增强连接性"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"蓝牙 AVRCP 版本"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"选择蓝牙 AVRCP 版本"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"蓝牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 26ddfb1..e04651c 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用絕對音量功能"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"啟用 Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"強化連線功能"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"選擇藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"藍牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 72ea043..a1ae6b6 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用絕對音量功能"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"啟用 Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"加強型連線"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"選取藍牙 AVRCP 版本"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"藍牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 6b8739f..2dafad8 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -257,7 +257,6 @@
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bonisa amadivayisi e-Bluetooth ngaphandle kwamagama"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Khubaza ivolumu ngokuphelele"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Nika amandla i-Gabeldorsche"</string>
-    <string name="enhanced_connectivity" msgid="7201127377781666804">"Ukuxhumeka Okuthuthukisiwe"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Inguqulo ye-Bluetooth ye-AVRCP"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Khetha inguqulo ye-Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Inguqulo ye-Bluetooth MAP"</string>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 18c2957..4eea8ad 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -112,7 +112,6 @@
         Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
         Settings.Secure.VR_DISPLAY_MODE,
         Settings.Secure.NOTIFICATION_BADGING,
-        Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED,
         Settings.Secure.NOTIFICATION_DISMISS_RTL,
         Settings.Secure.QS_AUTO_ADDED_TILES,
         Settings.Secure.SCREENSAVER_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index dd94d2e..a02d67f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -149,5 +149,6 @@
         VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_APP, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_USER, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 91f3f4a..c68ddbd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -189,7 +189,6 @@
         VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_NOTIFICATION_SNOOZE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.NOTIFICATION_HISTORY_ENABLED, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Secure.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index c1543fd..bfd5b1cc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -81,6 +81,7 @@
         sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_START_TIME);
         sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
         sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
+        sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
     }
 
     private interface SettingsLookup {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index df0137d..fa06e14 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -761,8 +761,8 @@
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
                 GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
         dumpSetting(s, p,
-                Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
-                GlobalSettingsProto.Gpu.ANGLE_WHITELIST);
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST,
+                GlobalSettingsProto.Gpu.ANGLE_ALLOWLIST);
         dumpSetting(s, p,
                 Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
                 GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index e49fd6f..4bb8f45 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -389,6 +389,7 @@
                     Settings.Global.NITZ_UPDATE_DIFF,
                     Settings.Global.NITZ_UPDATE_SPACING,
                     Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+                    Settings.Global.NOTIFICATION_FEEDBACK_ENABLED,
                     Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
                     Settings.Global.NSD_ON,
                     Settings.Global.NTP_SERVER,
@@ -502,7 +503,7 @@
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
-                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST,
                     Settings.Global.GAME_DRIVER_ALL_APPS,
                     Settings.Global.GAME_DRIVER_OPT_IN_APPS,
                     Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS,
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 3c641af..ed870f8 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -210,8 +210,98 @@
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size" />
 
-    <!-- Buttons to remove this view when no longer needed -->
-    <include
-        layout="@layout/qs_media_panel_options"
-        android:visibility="gone" />
+    <!-- Constraints are set here as they are the same regardless of host -->
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+        android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        android:id="@+id/media_text"
+        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+        android:textColor="@color/media_primary_text"
+        android:text="@string/controls_media_title"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/remove_text"
+        app:layout_constraintVertical_chainStyle="spread_inside"/>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        android:id="@+id/remove_text"
+        android:fontFamily="@*android:string/config_headlineFontFamily"
+        android:singleLine="true"
+        android:textColor="@color/media_primary_text"
+        android:text="@string/controls_media_close_session"
+        app:layout_constraintTop_toBottomOf="@id/media_text"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/settings"/>
+
+    <FrameLayout
+        android:id="@+id/settings"
+        android:background="@drawable/qs_media_light_source"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+        android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/remove_text">
+
+        <TextView
+            android:layout_gravity="bottom"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+            android:textColor="@android:color/white"
+            android:text="@string/controls_media_settings_button" />
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/cancel"
+        android:background="@drawable/qs_media_light_source"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/dismiss" >
+
+        <TextView
+            android:layout_gravity="bottom"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+            android:textColor="@android:color/white"
+            android:text="@string/cancel" />
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/dismiss"
+        android:background="@drawable/qs_media_light_source"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent">
+
+        <TextView
+            android:layout_gravity="bottom"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+            android:textColor="@android:color/white"
+            android:text="@string/controls_media_dismiss_button"
+        />
+    </FrameLayout>
 </com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/qs_media_panel_options.xml b/packages/SystemUI/res/layout/qs_media_panel_options.xml
deleted file mode 100644
index e72c0e8..0000000
--- a/packages/SystemUI/res/layout/qs_media_panel_options.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/qs_media_controls_options"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:gravity="center"
-    android:padding="16dp"
-    android:orientation="vertical">
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        android:layout_weight="1"
-        android:minWidth="48dp"
-        android:layout_gravity="start|bottom"
-        android:gravity="bottom"
-        android:id="@+id/remove"
-        android:orientation="horizontal">
-        <ImageView
-            android:layout_width="18dp"
-            android:layout_height="18dp"
-            android:id="@+id/remove_icon"
-            android:layout_marginEnd="16dp"
-            android:tint="@color/media_primary_text"
-            android:src="@drawable/ic_clear"/>
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/remove_text"
-            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-            android:singleLine="true"
-            android:textColor="@color/media_primary_text"
-            android:text="@string/controls_media_close_session" />
-    </LinearLayout>
-    <TextView
-        android:id="@+id/cancel"
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        android:layout_weight="1"
-        android:minWidth="48dp"
-        android:layout_gravity="end|bottom"
-        android:gravity="bottom"
-        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-        android:textColor="@android:color/white"
-        android:text="@string/cancel" />
-</LinearLayout>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2ad0cab..fa620df 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -161,10 +161,6 @@
     <!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
     <integer name="ambient_notification_extension_time">10000</integer>
 
-    <!-- In multi-window, determines whether the stack where recents lives should grow from
-         the smallest position when being launched. -->
-    <bool name="recents_grow_in_multiwindow">true</bool>
-
     <!-- Animation duration when using long press on recents to dock -->
     <integer name="long_press_dock_anim_duration">250</integer>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 77d3f45..823c1ff 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2799,7 +2799,7 @@
     <!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=NONE] -->
     <string name="controls_media_close_session">Hide the current session.</string>
     <!-- Label for a button that will hide media controls [CHAR_LIMIT=30] -->
-    <string name="controls_media_dismiss_button">Hide</string>
+    <string name="controls_media_dismiss_button">Dismiss</string>
     <!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
     <string name="controls_media_resume">Resume</string>
     <!-- Label for button to go to media control settings screen [CHAR_LIMIT=30] -->
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 8748926..27863ba 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -697,6 +697,9 @@
         pw.print("  desiredHeight: "); pw.println(getDesiredHeightString());
         pw.print("  suppressNotif: "); pw.println(shouldSuppressNotification());
         pw.print("  autoExpand:    "); pw.println(shouldAutoExpand());
+        if (mExpandedView != null) {
+            mExpandedView.dump(fd, pw, args);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index bb57219..c5639ea 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -84,6 +84,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
+import com.android.systemui.bubbles.animation.StackAnimationController;
 import com.android.systemui.bubbles.dagger.BubbleModule;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
@@ -173,6 +174,12 @@
     @Nullable private BubbleStackView mStackView;
     private BubbleIconFactory mBubbleIconFactory;
 
+    /**
+     * The relative position of the stack when we removed it and nulled it out. If the stack is
+     * re-created, it will re-appear at this position.
+     */
+    @Nullable private BubbleStackView.RelativeStackPosition mPositionFromRemovedStack;
+
     // Tracks the id of the current (foreground) user.
     private int mCurrentUserId;
     // Saves notification keys of active bubbles when users are switched.
@@ -736,6 +743,7 @@
                     mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
                     mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
                     this::hideCurrentInputMethod);
+            mStackView.setStackStartPosition(mPositionFromRemovedStack);
             mStackView.addView(mBubbleScrim);
             if (mExpandListener != null) {
                 mStackView.setExpandListener(mExpandListener);
@@ -806,6 +814,7 @@
         try {
             mAddedToWindowManager = false;
             if (mStackView != null) {
+                mPositionFromRemovedStack = mStackView.getRelativeStackPosition();
                 mWindowManager.removeView(mStackView);
                 mStackView.removeView(mBubbleScrim);
                 mStackView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e26aa55..d0f6181 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -34,6 +34,7 @@
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 
+import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -77,6 +78,9 @@
 import com.android.systemui.recents.TriangleShape;
 import com.android.systemui.statusbar.AlphaOptimizedButton;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * Container for the expanded bubble view, handles rendering the caret and settings icon.
  */
@@ -458,15 +462,6 @@
         mPointerView.setBackground(mPointerDrawable);
     }
 
-    /**
-     * Hides the IME if it's showing. This is currently done by dispatching a back press to the AV.
-     */
-    void hideImeIfVisible() {
-        if (mKeyboardVisible) {
-            performBackPressIfNeeded();
-        }
-    }
-
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
@@ -602,14 +597,17 @@
      */
     void update(Bubble bubble) {
         if (DEBUG_BUBBLE_EXPANDED_VIEW) {
-            Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
+            Log.d(TAG, "update: bubble=" + bubble);
+        }
+        if (mStackView == null) {
+            Log.w(TAG, "Stack is null for bubble: " + bubble);
+            return;
         }
         boolean isNew = mBubble == null || didBackingContentChange(bubble);
         if (isNew || bubble != null && bubble.getKey().equals(mBubble.getKey())) {
             mBubble = bubble;
             mSettingsIcon.setContentDescription(getResources().getString(
                     R.string.bubbles_settings_button_description, bubble.getAppName()));
-
             mSettingsIcon.setAccessibilityDelegate(
                     new AccessibilityDelegate() {
                         @Override
@@ -817,4 +815,15 @@
         }
         return null;
     }
+
+    /**
+     * Description of current expanded view state.
+     */
+    public void dump(
+            @NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        pw.print("BubbleExpandedView");
+        pw.print("  taskId:               "); pw.println(mTaskId);
+        pw.print("  activityViewStatus:   "); pw.println(mActivityViewStatus);
+        pw.print("  stackView:            "); pw.println(mStackView);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index ea12c95..ec9644a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -253,13 +253,8 @@
 
     /** Layout change listener that moves the stack to the nearest valid position on rotation. */
     private OnLayoutChangeListener mOrientationChangedListener;
-    /** Whether the stack was on the left side of the screen prior to rotation. */
-    private boolean mWasOnLeftBeforeRotation = false;
-    /**
-     * How far down the screen the stack was before rotation, in terms of percentage of the way down
-     * the allowable region. Defaults to -1 if not set.
-     */
-    private float mVerticalPosPercentBeforeRotation = -1;
+
+    @Nullable private RelativeStackPosition mRelativeStackPositionBeforeRotation;
 
     private int mMaxBubbles;
     private int mBubbleSize;
@@ -940,9 +935,10 @@
                         mExpandedViewContainer.setTranslationY(getExpandedViewY());
                         mExpandedViewContainer.setAlpha(1f);
                     }
-                    if (mVerticalPosPercentBeforeRotation >= 0) {
-                        mStackAnimationController.moveStackToSimilarPositionAfterRotation(
-                                mWasOnLeftBeforeRotation, mVerticalPosPercentBeforeRotation);
+                    if (mRelativeStackPositionBeforeRotation != null) {
+                        mStackAnimationController.setStackPosition(
+                                mRelativeStackPositionBeforeRotation);
+                        mRelativeStackPositionBeforeRotation = null;
                     }
                     removeOnLayoutChangeListener(mOrientationChangedListener);
                 };
@@ -1081,11 +1077,10 @@
                     final Bubble bubble = mBubbleData.getSelectedBubble();
                     if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
                         final Intent intent = bubble.getSettingsIntent(mContext);
-                        collapseStack(() -> {
-                            mContext.startActivityAsUser(intent, bubble.getUser());
-                            logBubbleEvent(bubble,
-                                    SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
-                        });
+                        mBubbleData.setExpanded(false);
+                        mContext.startActivityAsUser(intent, bubble.getUser());
+                        logBubbleEvent(bubble,
+                                SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
                     }
                 });
 
@@ -1190,13 +1185,7 @@
                 com.android.internal.R.dimen.status_bar_height);
         mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
 
-        final RectF allowablePos = mStackAnimationController.getAllowableStackPositionRegion();
-        mWasOnLeftBeforeRotation = mStackAnimationController.isStackOnLeftSide();
-        mVerticalPosPercentBeforeRotation =
-                (mStackAnimationController.getStackPosition().y - allowablePos.top)
-                        / (allowablePos.bottom - allowablePos.top);
-        mVerticalPosPercentBeforeRotation =
-                Math.max(0f, Math.min(1f, mVerticalPosPercentBeforeRotation));
+        mRelativeStackPositionBeforeRotation = mStackAnimationController.getRelativeStackPosition();
         addOnLayoutChangeListener(mOrientationChangedListener);
         hideFlyoutImmediate();
 
@@ -1460,7 +1449,7 @@
         if (getBubbleCount() == 0 && mShouldShowUserEducation) {
             // Override the default stack position if we're showing user education.
             mStackAnimationController.setStackPosition(
-                    mStackAnimationController.getDefaultStartPosition());
+                    mStackAnimationController.getStartPosition());
         }
 
         if (getBubbleCount() == 0) {
@@ -1675,7 +1664,7 @@
             // Post so we have height of mUserEducationView
             mUserEducationView.post(() -> {
                 final int viewHeight = mUserEducationView.getHeight();
-                PointF stackPosition = mStackAnimationController.getDefaultStartPosition();
+                PointF stackPosition = mStackAnimationController.getStartPosition();
                 final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
                 mUserEducationView.setTranslationY(translationY);
                 mUserEducationView.animate()
@@ -1769,36 +1758,6 @@
         }
     }
 
-    /**
-     * Dismiss the stack of bubbles.
-     *
-     * @deprecated
-     */
-    @Deprecated
-    void stackDismissed(int reason) {
-        if (DEBUG_BUBBLE_STACK_VIEW) {
-            Log.d(TAG, "stackDismissed: reason=" + reason);
-        }
-        mBubbleData.dismissAll(reason);
-        logBubbleEvent(null /* no bubble associated with bubble stack dismiss */,
-                SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
-    }
-
-    /**
-     * @deprecated use {@link #setExpanded(boolean)} and
-     * {@link BubbleData#setSelectedBubble(Bubble)}
-     */
-    @Deprecated
-    @MainThread
-    void collapseStack(Runnable endRunnable) {
-        if (DEBUG_BUBBLE_STACK_VIEW) {
-            Log.d(TAG, "collapseStack(endRunnable)");
-        }
-        mBubbleData.setExpanded(false);
-        // TODO - use the runnable at end of animation
-        endRunnable.run();
-    }
-
     void showExpandedViewContents(int displayId) {
         if (mExpandedBubble != null
                 && mExpandedBubble.getExpandedView() != null
@@ -2771,10 +2730,18 @@
                 .floatValue();
     }
 
+    public void setStackStartPosition(RelativeStackPosition position) {
+        mStackAnimationController.setStackStartPosition(position);
+    }
+
     public PointF getStackPosition() {
         return mStackAnimationController.getStackPosition();
     }
 
+    public RelativeStackPosition getRelativeStackPosition() {
+        return mStackAnimationController.getRelativeStackPosition();
+    }
+
     /**
      * Logs the bubble UI event.
      *
@@ -2828,4 +2795,47 @@
         }
         return bubbles;
     }
+
+    /**
+     * Representation of stack position that uses relative properties rather than absolute
+     * coordinates. This is used to maintain similar stack positions across configuration changes.
+     */
+    public static class RelativeStackPosition {
+        /** Whether to place the stack at the leftmost allowed position. */
+        private boolean mOnLeft;
+
+        /**
+         * How far down the vertically allowed region to place the stack. For example, if the stack
+         * allowed region is between y = 100 and y = 1100 and this is 0.2f, we'll place the stack at
+         * 100 + (0.2f * 1000) = 300.
+         */
+        private float mVerticalOffsetPercent;
+
+        public RelativeStackPosition(boolean onLeft, float verticalOffsetPercent) {
+            mOnLeft = onLeft;
+            mVerticalOffsetPercent = clampVerticalOffsetPercent(verticalOffsetPercent);
+        }
+
+        /** Constructs a relative position given a region and a point in that region. */
+        public RelativeStackPosition(PointF position, RectF region) {
+            mOnLeft = position.x < region.width() / 2;
+            mVerticalOffsetPercent =
+                    clampVerticalOffsetPercent((position.y - region.top) / region.height());
+        }
+
+        /** Ensures that the offset percent is between 0f and 1f. */
+        private float clampVerticalOffsetPercent(float offsetPercent) {
+            return Math.max(0f, Math.min(1f, offsetPercent));
+        }
+
+        /**
+         * Given an allowable stack position region, returns the point within that region
+         * represented by this relative position.
+         */
+        public PointF getAbsolutePositionInRegion(RectF region) {
+            return new PointF(
+                    mOnLeft ? region.left : region.right,
+                    region.top + mVerticalOffsetPercent * region.height());
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index 1929fc4..5749169 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -103,11 +103,12 @@
 
     @Override
     protected void onPostExecute(BubbleViewInfo viewInfo) {
-        if (viewInfo != null) {
-            mBubble.setViewInfo(viewInfo);
-            if (mCallback != null && !isCancelled()) {
-                mCallback.onBubbleViewsReady(mBubble);
-            }
+        if (isCancelled() || viewInfo == null) {
+            return;
+        }
+        mBubble.setViewInfo(viewInfo);
+        if (mCallback != null) {
+            mCallback.onBubbleViewsReady(mBubble);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index b378469..e835ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -35,6 +35,7 @@
 import androidx.dynamicanimation.animation.SpringForce;
 
 import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleStackView;
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.systemui.util.animation.PhysicsAnimator;
 import com.android.systemui.util.magnetictarget.MagnetizedObject;
@@ -125,6 +126,9 @@
      */
     private Rect mAnimatingToBounds = new Rect();
 
+    /** Initial starting location for the stack. */
+    @Nullable private BubbleStackView.RelativeStackPosition mStackStartPosition;
+
     /** Whether or not the stack's start position has been set. */
     private boolean mStackMovedToStartPosition = false;
 
@@ -431,21 +435,6 @@
         return stackPos;
     }
 
-    /**
-     * Moves the stack in response to rotation. We keep it in the most similar position by keeping
-     * it on the same side, and positioning it the same percentage of the way down the screen
-     * (taking status bar/nav bar into account by using the allowable region's height).
-     */
-    public void moveStackToSimilarPositionAfterRotation(boolean wasOnLeft, float verticalPercent) {
-        final RectF allowablePos = getAllowableStackPositionRegion();
-        final float allowableRegionHeight = allowablePos.bottom - allowablePos.top;
-
-        final float x = wasOnLeft ? allowablePos.left : allowablePos.right;
-        final float y = (allowableRegionHeight * verticalPercent) + allowablePos.top;
-
-        setStackPosition(new PointF(x, y));
-    }
-
     /** Description of current animation controller state. */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("StackAnimationController state:");
@@ -815,7 +804,7 @@
         } else {
             // When all children are removed ensure stack position is sane
             setStackPosition(mRestingStackPosition == null
-                    ? getDefaultStartPosition()
+                    ? getStartPosition()
                     : mRestingStackPosition);
 
             // Remove the stack from the coordinator since we don't have any bubbles and aren't
@@ -868,7 +857,7 @@
         mLayout.setVisibility(View.INVISIBLE);
         mLayout.post(() -> {
             setStackPosition(mRestingStackPosition == null
-                    ? getDefaultStartPosition()
+                    ? getStartPosition()
                     : mRestingStackPosition);
             mStackMovedToStartPosition = true;
             mLayout.setVisibility(View.VISIBLE);
@@ -938,15 +927,47 @@
         }
     }
 
-    /** Returns the default stack position, which is on the top left. */
-    public PointF getDefaultStartPosition() {
-        boolean isRtl = mLayout != null
-                && mLayout.getResources().getConfiguration().getLayoutDirection()
-                == View.LAYOUT_DIRECTION_RTL;
-        return new PointF(isRtl
-                        ? getAllowableStackPositionRegion().right
-                        : getAllowableStackPositionRegion().left,
-                getAllowableStackPositionRegion().top + mStackStartingVerticalOffset);
+    public void setStackPosition(BubbleStackView.RelativeStackPosition position) {
+        setStackPosition(position.getAbsolutePositionInRegion(getAllowableStackPositionRegion()));
+    }
+
+    public BubbleStackView.RelativeStackPosition getRelativeStackPosition() {
+        return new BubbleStackView.RelativeStackPosition(
+                mStackPosition, getAllowableStackPositionRegion());
+    }
+
+    /**
+     * Sets the starting position for the stack, where it will be located when the first bubble is
+     * added.
+     */
+    public void setStackStartPosition(BubbleStackView.RelativeStackPosition position) {
+        mStackStartPosition = position;
+    }
+
+    /**
+     * Returns the starting stack position. If {@link #setStackStartPosition} was called, this will
+     * return that position - otherwise, a reasonable default will be returned.
+     */
+    @Nullable public PointF getStartPosition() {
+        if (mLayout == null) {
+            return null;
+        }
+
+        if (mStackStartPosition == null) {
+            // Start on the left if we're in LTR, right otherwise.
+            final boolean startOnLeft =
+                    mLayout.getResources().getConfiguration().getLayoutDirection()
+                            != View.LAYOUT_DIRECTION_RTL;
+
+            final float startingVerticalOffset = mLayout.getResources().getDimensionPixelOffset(
+                    R.dimen.bubble_stack_starting_offset_y);
+
+            mStackStartPosition = new BubbleStackView.RelativeStackPosition(
+                    startOnLeft,
+                    startingVerticalOffset / getAllowableStackPositionRegion().height());
+        }
+
+        return mStackStartPosition.getAbsolutePositionInRegion(getAllowableStackPositionRegion());
     }
 
     private boolean isStackPositionSet() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt b/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
new file mode 100644
index 0000000..cca0f16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.controls
+
+import android.content.ComponentName
+import android.graphics.drawable.Icon
+import androidx.annotation.GuardedBy
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Icon cache for custom icons sent with controls.
+ *
+ * It assumes that only one component can be current at the time, to minimize the number of icons
+ * stored at a given time.
+ */
+@Singleton
+class CustomIconCache @Inject constructor() {
+
+    private var currentComponent: ComponentName? = null
+    @GuardedBy("cache")
+    private val cache: MutableMap<String, Icon> = LinkedHashMap()
+
+    /**
+     * Store an icon in the cache.
+     *
+     * If the icons currently stored do not correspond to the component to be stored, the cache is
+     * cleared first.
+     */
+    fun store(component: ComponentName, controlId: String, icon: Icon?) {
+        if (component != currentComponent) {
+            clear()
+            currentComponent = component
+        }
+        synchronized(cache) {
+            if (icon != null) {
+                cache.put(controlId, icon)
+            } else {
+                cache.remove(controlId)
+            }
+        }
+    }
+
+    /**
+     * Retrieves a custom icon stored in the cache.
+     *
+     * It will return null if the component requested is not the one whose icons are stored, or if
+     * there is no icon cached for that id.
+     */
+    fun retrieve(component: ComponentName, controlId: String): Icon? {
+        if (component != currentComponent) return null
+        return synchronized(cache) {
+            cache.get(controlId)
+        }
+    }
+
+    private fun clear() {
+        synchronized(cache) {
+            cache.clear()
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index ff40a8a..f68388d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -29,6 +29,7 @@
 import androidx.recyclerview.widget.RecyclerView
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.CustomIconCache
 import com.android.systemui.controls.controller.ControlsControllerImpl
 import com.android.systemui.controls.controller.StructureInfo
 import com.android.systemui.globalactions.GlobalActionsComponent
@@ -42,7 +43,8 @@
 class ControlsEditingActivity @Inject constructor(
     private val controller: ControlsControllerImpl,
     broadcastDispatcher: BroadcastDispatcher,
-    private val globalActionsComponent: GlobalActionsComponent
+    private val globalActionsComponent: GlobalActionsComponent,
+    private val customIconCache: CustomIconCache
 ) : LifecycleActivity() {
 
     companion object {
@@ -170,7 +172,7 @@
 
     private fun setUpList() {
         val controls = controller.getFavoritesForStructure(component, structure)
-        model = FavoritesModel(component, controls, favoritesModelCallback)
+        model = FavoritesModel(customIconCache, component, controls, favoritesModelCallback)
         val elevation = resources.getFloat(R.dimen.control_card_elevation)
         val recyclerView = requireViewById<RecyclerView>(R.id.list)
         recyclerView.alpha = 0.0f
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
index 4ef64a5..ad0e7a5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
@@ -114,11 +114,27 @@
     val controlStatus: ControlStatus
 ) : ElementWrapper(), ControlInterface by controlStatus
 
+private fun nullIconGetter(_a: ComponentName, _b: String): Icon? = null
+
 data class ControlInfoWrapper(
     override val component: ComponentName,
     val controlInfo: ControlInfo,
     override var favorite: Boolean
 ) : ElementWrapper(), ControlInterface {
+
+    var customIconGetter: (ComponentName, String) -> Icon? = ::nullIconGetter
+        private set
+
+    // Separate constructor so the getter is not used in auto-generated methods
+    constructor(
+        component: ComponentName,
+        controlInfo: ControlInfo,
+        favorite: Boolean,
+        customIconGetter: (ComponentName, String) -> Icon?
+    ): this(component, controlInfo, favorite) {
+        this.customIconGetter = customIconGetter
+    }
+
     override val controlId: String
         get() = controlInfo.controlId
     override val title: CharSequence
@@ -128,8 +144,7 @@
     override val deviceType: Int
         get() = controlInfo.deviceType
     override val customIcon: Icon?
-        // Will need to address to support for edit activity
-        get() = null
+        get() = customIconGetter(component, controlId)
 }
 
 data class DividerWrapper(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
index 5242501..f9ce636 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
@@ -21,6 +21,7 @@
 import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.RecyclerView
 import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.CustomIconCache
 import com.android.systemui.controls.controller.ControlInfo
 import java.util.Collections
 
@@ -35,6 +36,7 @@
  * @property favoritesModelCallback callback to notify on first change and empty favorites
  */
 class FavoritesModel(
+    private val customIconCache: CustomIconCache,
     private val componentName: ComponentName,
     favorites: List<ControlInfo>,
     private val favoritesModelCallback: FavoritesModelCallback
@@ -83,7 +85,7 @@
         }
 
     override val elements: List<ElementWrapper> = favorites.map {
-        ControlInfoWrapper(componentName, it, true)
+        ControlInfoWrapper(componentName, it, true, customIconCache::retrieve)
     } + DividerWrapper()
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 22d6b6b..e15380b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -92,7 +92,7 @@
     override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) {
         bouncerOrRun(Action(cvh.cws.ci.controlId, {
             cvh.action(FloatAction(templateId, newValue))
-        }, true /* blockable */))
+        }, false /* blockable */))
     }
 
     override fun longPress(cvh: ControlViewHolder) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 1eb7e21..5f75c96 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -44,6 +44,7 @@
 import android.widget.TextView
 import com.android.systemui.R
 import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.CustomIconCache
 import com.android.systemui.controls.controller.ControlInfo
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.controller.StructureInfo
@@ -75,7 +76,8 @@
     @Main val sharedPreferences: SharedPreferences,
     val controlActionCoordinator: ControlActionCoordinator,
     private val activityStarter: ActivityStarter,
-    private val shadeController: ShadeController
+    private val shadeController: ShadeController,
+    private val iconCache: CustomIconCache
 ) : ControlsUiController {
 
     companion object {
@@ -502,6 +504,7 @@
         controls.forEach { c ->
             controlsById.get(ControlKey(componentName, c.getControlId()))?.let {
                 Log.d(ControlsUiController.TAG, "onRefreshState() for id: " + c.getControlId())
+                iconCache.store(componentName, c.controlId, c.customIcon)
                 val cws = ControlWithState(componentName, it.ci, c)
                 val key = ControlKey(componentName, c.getControlId())
                 controlsById.put(key, cws)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index 900c11f..9fdbb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -29,7 +29,6 @@
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
 import com.android.systemui.onehanded.dagger.OneHandedModule;
-import com.android.systemui.pip.phone.PipMenuActivity;
 import com.android.systemui.pip.phone.dagger.PipModule;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.InjectionInflationController;
@@ -133,9 +132,4 @@
      * Member injection into the supplied argument.
      */
     void inject(KeyguardSliceProvider keyguardSliceProvider);
-
-    /**
-     * Member injection into the supplied argument.
-     */
-    void inject(PipMenuActivity pipMenuActivity);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index de53168..7f610d1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -3,7 +3,6 @@
 import android.content.Context
 import android.content.Intent
 import android.content.res.Configuration
-import android.graphics.Color
 import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
 import android.util.Log
 import android.util.MathUtils
@@ -151,7 +150,7 @@
         pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
         mediaCarouselScrollHandler = MediaCarouselScrollHandler(mediaCarousel, pageIndicator,
                 executor, mediaManager::onSwipeToDismiss, this::updatePageIndicatorLocation,
-                falsingManager)
+                this::closeGuts, falsingManager)
         isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
         inflateSettingsButton()
         mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
@@ -470,6 +469,12 @@
         }
     }
 
+    fun closeGuts() {
+        mediaPlayers.values.forEach {
+            it.closeGuts(true)
+        }
+    }
+
     /**
      * Update the size of the carousel, remeasuring it if necessary.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index 3096908..77cac50 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -56,6 +56,7 @@
     private val mainExecutor: DelayableExecutor,
     private val dismissCallback: () -> Unit,
     private var translationChangedListener: () -> Unit,
+    private val closeGuts: () -> Unit,
     private val falsingManager: FalsingManager
 ) {
     /**
@@ -452,6 +453,7 @@
         val nowScrolledIn = scrollIntoCurrentMedia != 0
         if (newIndex != activeMediaIndex || wasScrolledIn != nowScrolledIn) {
             activeMediaIndex = newIndex
+            closeGuts()
             updatePlayerVisibilities()
         }
         val relativeLocation = activeMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 3fc162e..e55678dc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media;
 
+import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;
+
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -45,6 +47,7 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.util.animation.TransitionLayout;
 
 import java.util.List;
@@ -52,6 +55,8 @@
 
 import javax.inject.Inject;
 
+import dagger.Lazy;
+
 /**
  * A view controller used for Media Playback.
  */
@@ -59,6 +64,8 @@
     private static final String TAG = "MediaControlPanel";
     private static final float DISABLED_ALPHA = 0.38f;
 
+    private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
+
     // Button IDs for QS controls
     static final int[] ACTION_IDS = {
             R.id.action0,
@@ -78,6 +85,8 @@
     private MediaViewController mMediaViewController;
     private MediaSession.Token mToken;
     private MediaController mController;
+    private KeyguardDismissUtil mKeyguardDismissUtil;
+    private Lazy<MediaDataManager> mMediaDataManagerLazy;
     private int mBackgroundColor;
     private int mAlbumArtSize;
     private int mAlbumArtRadius;
@@ -93,12 +102,15 @@
     @Inject
     public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
             ActivityStarter activityStarter, MediaViewController mediaViewController,
-            SeekBarViewModel seekBarViewModel) {
+            SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
+            KeyguardDismissUtil keyguardDismissUtil) {
         mContext = context;
         mBackgroundExecutor = backgroundExecutor;
         mActivityStarter = activityStarter;
         mSeekBarViewModel = seekBarViewModel;
         mMediaViewController = mediaViewController;
+        mMediaDataManagerLazy = lazyMediaDataManager;
+        mKeyguardDismissUtil = keyguardDismissUtil;
         loadDimens();
 
         mViewOutlineProvider = new ViewOutlineProvider() {
@@ -174,6 +186,21 @@
         mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
         mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
         mMediaViewController.attach(player);
+
+        mViewHolder.getPlayer().setOnLongClickListener(v -> {
+            if (!mMediaViewController.isGutsVisible()) {
+                mMediaViewController.openGuts();
+                return true;
+            } else {
+                return false;
+            }
+        });
+        mViewHolder.getCancel().setOnClickListener(v -> {
+            closeGuts();
+        });
+        mViewHolder.getSettings().setOnClickListener(v -> {
+            mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+        });
     }
 
     /**
@@ -205,6 +232,7 @@
         PendingIntent clickIntent = data.getClickIntent();
         if (clickIntent != null) {
             mViewHolder.getPlayer().setOnClickListener(v -> {
+                if (mMediaViewController.isGutsVisible()) return;
                 mActivityStarter.postStartActivityDismissingKeyguard(clickIntent);
             });
         }
@@ -329,14 +357,38 @@
         final MediaController controller = getController();
         mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
 
-        // Set up long press menu
-        // TODO: b/156036025 bring back media guts
+        // Dismiss
+        mViewHolder.getDismiss().setOnClickListener(v -> {
+            if (data.getNotificationKey() != null) {
+                closeGuts();
+                mKeyguardDismissUtil.executeWhenUnlocked(() -> {
+                    mMediaDataManagerLazy.get().dismissMediaData(data.getNotificationKey(),
+                            MediaViewController.GUTS_ANIMATION_DURATION + 100);
+                    return true;
+                }, /* requiresShadeOpen */ true);
+            } else {
+                Log.w(TAG, "Dismiss media with null notification. Token uid="
+                        + data.getToken().getUid());
+            }
+        });
 
         // TODO: We don't need to refresh this state constantly, only if the state actually changed
         // to something which might impact the measurement
         mMediaViewController.refreshState();
     }
 
+    /**
+     * Close the guts for this player.
+     * @param immediate {@code true} if it should be closed without animation
+     */
+    public void closeGuts(boolean immediate) {
+        mMediaViewController.closeGuts(immediate);
+    }
+
+    private void closeGuts() {
+        closeGuts(false);
+    }
+
     @UiThread
     private Drawable scaleDrawable(Icon icon) {
         if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index d82150f2..8a51c85 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -48,6 +48,7 @@
 import com.android.systemui.statusbar.notification.row.HybridGroupManager
 import com.android.systemui.util.Assert
 import com.android.systemui.util.Utils
+import com.android.systemui.util.concurrency.DelayableExecutor
 import java.io.FileDescriptor
 import java.io.IOException
 import java.io.PrintWriter
@@ -90,7 +91,7 @@
 class MediaDataManager(
     private val context: Context,
     @Background private val backgroundExecutor: Executor,
-    @Main private val foregroundExecutor: Executor,
+    @Main private val foregroundExecutor: DelayableExecutor,
     private val mediaControllerFactory: MediaControllerFactory,
     private val broadcastDispatcher: BroadcastDispatcher,
     dumpManager: DumpManager,
@@ -107,7 +108,7 @@
     constructor(
         context: Context,
         @Background backgroundExecutor: Executor,
-        @Main foregroundExecutor: Executor,
+        @Main foregroundExecutor: DelayableExecutor,
         mediaControllerFactory: MediaControllerFactory,
         dumpManager: DumpManager,
         broadcastDispatcher: BroadcastDispatcher,
@@ -183,10 +184,7 @@
         val listenersCopy = listeners.toSet()
         val toRemove = mediaEntries.filter { it.value.packageName == packageName }
         toRemove.forEach {
-            mediaEntries.remove(it.key)
-            listenersCopy.forEach { listener ->
-                listener.onMediaDataRemoved(it.key)
-            }
+            removeEntry(it.key, listenersCopy)
         }
     }
 
@@ -269,6 +267,18 @@
         }
     }
 
+    private fun removeEntry(key: String, listenersCopy: Set<Listener>) {
+        mediaEntries.remove(key)
+        listenersCopy.forEach {
+            it.onMediaDataRemoved(key)
+        }
+    }
+
+    fun dismissMediaData(key: String, delay: Long) {
+        val listenersCopy = listeners.toSet()
+        foregroundExecutor.executeDelayed({ removeEntry(key, listenersCopy) }, delay)
+    }
+
     private fun loadMediaDataInBgForResumption(
         userId: Int,
         desc: MediaDescription,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index fc33391..70f01d5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -293,6 +293,13 @@
         return viewHost
     }
 
+    /**
+     * Close the guts in all players in [MediaCarouselController].
+     */
+    fun closeGuts() {
+        mediaCarouselController.closeGuts()
+    }
+
     private fun createUniqueObjectHost(): UniqueObjectHostView {
         val viewHost = UniqueObjectHostView(context)
         viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 38817d7..92eeed4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -37,6 +37,11 @@
     private val mediaHostStatesManager: MediaHostStatesManager
 ) {
 
+    companion object {
+        @JvmField
+        val GUTS_ANIMATION_DURATION = 500L
+    }
+
     /**
      * A listener when the current dimensions of the player change
      */
@@ -169,6 +174,12 @@
      */
     val expandedLayout = ConstraintSet()
 
+    /**
+     * Whether the guts are visible for the associated player.
+     */
+    var isGutsVisible = false
+        private set
+
     init {
         collapsedLayout.load(context, R.xml.media_collapsed)
         expandedLayout.load(context, R.xml.media_expanded)
@@ -189,6 +200,37 @@
         configurationController.removeCallback(configurationListener)
     }
 
+    /**
+     * Show guts with an animated transition.
+     */
+    fun openGuts() {
+        if (isGutsVisible) return
+        isGutsVisible = true
+        animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
+        setCurrentState(currentStartLocation,
+                currentEndLocation,
+                currentTransitionProgress,
+                applyImmediately = false)
+    }
+
+    /**
+     * Close the guts for the associated player.
+     *
+     * @param immediate if `false`, it will animate the transition.
+     */
+    @JvmOverloads
+    fun closeGuts(immediate: Boolean = false) {
+        if (!isGutsVisible) return
+        isGutsVisible = false
+        if (!immediate) {
+            animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
+        }
+        setCurrentState(currentStartLocation,
+                currentEndLocation,
+                currentTransitionProgress,
+                applyImmediately = immediate)
+    }
+
     private fun ensureAllMeasurements() {
         val mediaStates = mediaHostStatesManager.mediaHostStates
         for (entry in mediaStates) {
@@ -203,6 +245,24 @@
             if (expansion > 0) expandedLayout else collapsedLayout
 
     /**
+     * Set the views to be showing/hidden based on the [isGutsVisible] for a given
+     * [TransitionViewState].
+     */
+    private fun setGutsViewState(viewState: TransitionViewState) {
+        PlayerViewHolder.controlsIds.forEach { id ->
+            viewState.widgetStates.get(id)?.let { state ->
+                // Make sure to use the unmodified state if guts are not visible
+                state.alpha = if (isGutsVisible) 0f else state.alpha
+                state.gone = if (isGutsVisible) true else state.gone
+            }
+        }
+        PlayerViewHolder.gutsIds.forEach { id ->
+            viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
+            viewState.widgetStates.get(id)?.gone = !isGutsVisible
+        }
+    }
+
+    /**
      * Obtain a new viewState for a given media state. This usually returns a cached state, but if
      * it's not available, it will recreate one by measuring, which may be expensive.
      */
@@ -211,7 +271,7 @@
             return null
         }
         // Only a subset of the state is relevant to get a valid viewState. Let's get the cachekey
-        var cacheKey = getKey(state, tmpKey)
+        var cacheKey = getKey(state, isGutsVisible, tmpKey)
         val viewState = viewStates[cacheKey]
         if (viewState != null) {
             // we already have cached this measurement, let's continue
@@ -228,6 +288,7 @@
                         constraintSetForExpansion(state.expansion),
                         TransitionViewState())
 
+                setGutsViewState(result)
                 // We don't want to cache interpolated or null states as this could quickly fill up
                 // our cache. We only cache the start and the end states since the interpolation
                 // is cheap
@@ -252,11 +313,12 @@
         return result
     }
 
-    private fun getKey(state: MediaHostState, result: CacheKey): CacheKey {
+    private fun getKey(state: MediaHostState, guts: Boolean, result: CacheKey): CacheKey {
         result.apply {
             heightMeasureSpec = state.measurementInput?.heightMeasureSpec ?: 0
             widthMeasureSpec = state.measurementInput?.widthMeasureSpec ?: 0
             expansion = state.expansion
+            gutsVisible = guts
         }
         return result
     }
@@ -432,5 +494,6 @@
 private data class CacheKey(
     var widthMeasureSpec: Int = -1,
     var heightMeasureSpec: Int = -1,
-    var expansion: Float = 0.0f
+    var expansion: Float = 0.0f,
+    var gutsVisible: Boolean = false
 )
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 600fdc2..11551ac 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -23,6 +23,7 @@
 import android.widget.ImageView
 import android.widget.SeekBar
 import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintSet
 import com.android.systemui.R
 import com.android.systemui.util.animation.TransitionLayout
 
@@ -59,6 +60,11 @@
     val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
     val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
 
+    // Settings screen
+    val cancel = itemView.requireViewById<View>(R.id.cancel)
+    val dismiss = itemView.requireViewById<View>(R.id.dismiss)
+    val settings = itemView.requireViewById<View>(R.id.settings)
+
     init {
         (player.background as IlluminationDrawable).let {
             it.registerLightSource(seamless)
@@ -67,6 +73,9 @@
             it.registerLightSource(action2)
             it.registerLightSource(action3)
             it.registerLightSource(action4)
+            it.registerLightSource(cancel)
+            it.registerLightSource(dismiss)
+            it.registerLightSource(settings)
         }
     }
 
@@ -83,9 +92,6 @@
         }
     }
 
-    // Settings screen
-    val options = itemView.requireViewById<View>(R.id.qs_media_controls_options)
-
     companion object {
         /**
          * Creates a PlayerViewHolder.
@@ -105,5 +111,29 @@
                 progressTimes.layoutDirection = View.LAYOUT_DIRECTION_LTR
             }
         }
+
+        val controlsIds = setOf(
+                R.id.icon,
+                R.id.app_name,
+                R.id.album_art,
+                R.id.header_title,
+                R.id.header_artist,
+                R.id.media_seamless,
+                R.id.notification_media_progress_time,
+                R.id.media_progress_bar,
+                R.id.action0,
+                R.id.action1,
+                R.id.action2,
+                R.id.action3,
+                R.id.action4,
+                R.id.icon
+        )
+        val gutsIds = setOf(
+                R.id.media_text,
+                R.id.remove_text,
+                R.id.cancel,
+                R.id.dismiss,
+                R.id.settings
+        )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 7201931..4931388 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -53,16 +53,16 @@
     public static final int TRANSITION_DIRECTION_NONE = 0;
     public static final int TRANSITION_DIRECTION_SAME = 1;
     public static final int TRANSITION_DIRECTION_TO_PIP = 2;
-    public static final int TRANSITION_DIRECTION_TO_FULLSCREEN = 3;
-    public static final int TRANSITION_DIRECTION_TO_SPLIT_SCREEN = 4;
+    public static final int TRANSITION_DIRECTION_LEAVE_PIP = 3;
+    public static final int TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN = 4;
     public static final int TRANSITION_DIRECTION_REMOVE_STACK = 5;
 
     @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
             TRANSITION_DIRECTION_NONE,
             TRANSITION_DIRECTION_SAME,
             TRANSITION_DIRECTION_TO_PIP,
-            TRANSITION_DIRECTION_TO_FULLSCREEN,
-            TRANSITION_DIRECTION_TO_SPLIT_SCREEN,
+            TRANSITION_DIRECTION_LEAVE_PIP,
+            TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN,
             TRANSITION_DIRECTION_REMOVE_STACK
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -73,8 +73,8 @@
     }
 
     public static boolean isOutPipDirection(@TransitionDirection int direction) {
-        return direction == TRANSITION_DIRECTION_TO_FULLSCREEN
-                || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
+        return direction == TRANSITION_DIRECTION_LEAVE_PIP
+                || direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
     }
 
     private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 312d6d6..025341c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -23,12 +23,12 @@
 
 import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
 import static com.android.systemui.pip.PipAnimationController.isInPipDirection;
 import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
 
@@ -99,6 +99,7 @@
     private final Handler mUpdateHandler;
     private final PipBoundsHandler mPipBoundsHandler;
     private final PipAnimationController mPipAnimationController;
+    private final PipUiEventLogger mPipUiEventLoggerLogger;
     private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
     private final Rect mLastReportedBounds = new Rect();
     private final int mEnterExitAnimationDuration;
@@ -209,7 +210,8 @@
             @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
             @Nullable Divider divider,
             @NonNull DisplayController displayController,
-            @NonNull PipAnimationController pipAnimationController) {
+            @NonNull PipAnimationController pipAnimationController,
+            @NonNull PipUiEventLogger pipUiEventLogger) {
         mMainHandler = new Handler(Looper.getMainLooper());
         mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
         mPipBoundsHandler = boundsHandler;
@@ -217,6 +219,7 @@
                 .getInteger(R.integer.config_pipResizeAnimationDuration);
         mSurfaceTransactionHelper = surfaceTransactionHelper;
         mPipAnimationController = pipAnimationController;
+        mPipUiEventLoggerLogger = pipUiEventLogger;
         mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
         mSplitDivider = divider;
         displayController.addDisplayWindowListener(this);
@@ -279,14 +282,16 @@
             return;
         }
 
+        mPipUiEventLoggerLogger.log(
+                PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
         final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
         final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
                 != mPipBoundsHandler.getDisplayRotation();
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         final Rect destinationBounds = initialConfig.windowConfiguration.getBounds();
         final int direction = syncWithSplitScreenBounds(destinationBounds)
-                ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN
-                : TRANSITION_DIRECTION_TO_FULLSCREEN;
+                ? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+                : TRANSITION_DIRECTION_LEAVE_PIP;
         if (orientationDiffers) {
             // Send started callback though animation is ignored.
             sendOnPipTransitionStarted(direction);
@@ -303,7 +308,10 @@
             mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
                     mLastReportedBounds);
             tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
-            wct.setActivityWindowingMode(mToken, direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN
+            // We set to fullscreen here for now, but later it will be set to UNDEFINED for
+            // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
+            wct.setActivityWindowingMode(mToken,
+                    direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
                     ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                     : WINDOWING_MODE_FULLSCREEN);
             wct.setBounds(mToken, destinationBounds);
@@ -327,7 +335,7 @@
         wct.setWindowingMode(mToken, getOutPipWindowingMode());
         // Simply reset the activity mode set prior to the animation running.
         wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
-        if (mSplitDivider != null && direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN) {
+        if (mSplitDivider != null && direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
             wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
         }
     }
@@ -378,6 +386,9 @@
         mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
         mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
 
+        mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
+        mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
+
         if (mShouldDeferEnteringPip) {
             if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing");
             // if deferred, hide the surface till fixed rotation is completed
@@ -451,10 +462,11 @@
 
     private void sendOnPipTransitionStarted(
             @PipAnimationController.TransitionDirection int direction) {
+        final Rect pipBounds = new Rect(mLastReportedBounds);
         runOnMainHandler(() -> {
             for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
                 final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
-                callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction);
+                callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction, pipBounds);
             }
         });
     }
@@ -510,6 +522,7 @@
         mPictureInPictureParams = null;
         mInPip = false;
         mExitingPip = false;
+        mPipUiEventLoggerLogger.setTaskInfo(null);
     }
 
     @Override
@@ -625,7 +638,7 @@
      * {@link PictureInPictureParams} would affect the bounds.
      */
     private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
-        final boolean changed = (mPictureInPictureParams == null) ? true : !Objects.equals(
+        final boolean changed = (mPictureInPictureParams == null) || !Objects.equals(
                 mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
         if (changed) {
             mPictureInPictureParams = params;
@@ -842,7 +855,7 @@
         } else if (isOutPipDirection(direction)) {
             // If we are animating to fullscreen, then we need to reset the override bounds
             // on the task to ensure that the task "matches" the parent's bounds.
-            taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN)
+            taskBounds = (direction == TRANSITION_DIRECTION_LEAVE_PIP)
                     ? null : destinationBounds;
             applyWindowingModeChangeOnExit(wct, direction);
         } else {
@@ -970,7 +983,7 @@
         /**
          * Callback when the pip transition is started.
          */
-        void onPipTransitionStarted(ComponentName activity, int direction);
+        void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds);
 
         /**
          * Callback when the pip transition is finished.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
new file mode 100644
index 0000000..5e2cd9c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.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 com.android.systemui.pip;
+
+import android.app.TaskInfo;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+
+/**
+ * Helper class that ends PiP log to UiEvent, see also go/uievent
+ */
+@Singleton
+public class PipUiEventLogger {
+
+    private final UiEventLogger mUiEventLogger;
+
+    private TaskInfo mTaskInfo;
+
+    @Inject
+    public PipUiEventLogger(UiEventLogger uiEventLogger) {
+        mUiEventLogger = uiEventLogger;
+    }
+
+    public void setTaskInfo(TaskInfo taskInfo) {
+        mTaskInfo = taskInfo;
+    }
+
+    /**
+     * Sends log via UiEvent, reference go/uievent for how to debug locally
+     */
+    public void log(PipUiEventEnum event) {
+        if (mTaskInfo == null) {
+            return;
+        }
+        mUiEventLogger.log(event, mTaskInfo.userId, mTaskInfo.topActivity.getPackageName());
+    }
+
+    /**
+     * Enums for logging the PiP events to UiEvent
+     */
+    public enum PipUiEventEnum implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Activity enters picture-in-picture mode")
+        PICTURE_IN_PICTURE_ENTER(603),
+
+        @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
+        PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
+
+        @UiEvent(doc = "Removes picture-in-picture by tap close button")
+        PICTURE_IN_PICTURE_TAP_TO_REMOVE(605),
+
+        @UiEvent(doc = "Removes picture-in-picture by drag to dismiss area")
+        PICTURE_IN_PICTURE_DRAG_TO_REMOVE(606),
+
+        @UiEvent(doc = "Shows picture-in-picture menu")
+        PICTURE_IN_PICTURE_SHOW_MENU(607),
+
+        @UiEvent(doc = "Hides picture-in-picture menu")
+        PICTURE_IN_PICTURE_HIDE_MENU(608),
+
+        @UiEvent(doc = "Changes the aspect ratio of picture-in-picture window. This is inherited"
+                + " from previous Tron-based logging and currently not in use.")
+        PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
+
+        @UiEvent(doc = "User resize of the picture-in-picture window")
+        PICTURE_IN_PICTURE_RESIZE(610);
+
+        private final int mId;
+
+        PipUiEventEnum(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
index c715398..a133189 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
@@ -131,7 +131,7 @@
                         result = true;
                         break;
                     case AccessibilityNodeInfo.ACTION_EXPAND:
-                        mMotionHelper.expandPipToFullscreen();
+                        mMotionHelper.expandLeavePip();
                         result = true;
                         break;
                     default:
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 582cd04..9dfa864 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -47,6 +47,8 @@
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputConsumerController;
@@ -181,7 +183,7 @@
                     != WINDOWING_MODE_PINNED) {
                 return;
             }
-            mTouchHandler.getMotionHelper().expandPipToFullscreen(clearedTask /* skipAnimation */);
+            mTouchHandler.getMotionHelper().expandLeavePip(clearedTask /* skipAnimation */);
         }
     };
 
@@ -250,6 +252,7 @@
 
     @Inject
     public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
+            @PipMenuActivityClass Class<?> pipMenuActivityClass,
             DisplayController displayController,
             FloatingContentCoordinator floatingContentCoordinator,
             DeviceConfigProxy deviceConfig,
@@ -257,7 +260,8 @@
             PipSnapAlgorithm pipSnapAlgorithm,
             PipTaskOrganizer pipTaskOrganizer,
             SysUiState sysUiState,
-            ConfigurationController configController) {
+            ConfigurationController configController,
+            PipUiEventLogger pipUiEventLogger) {
         mContext = context;
         mActivityManager = ActivityManager.getService();
 
@@ -274,11 +278,12 @@
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mInputConsumerController = InputConsumerController.getPipInputConsumer();
         mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
-        mMenuController = new PipMenuActivityController(context, mMediaController,
-                mInputConsumerController);
+        mMenuController = new PipMenuActivityController(context, pipMenuActivityClass,
+                mMediaController, mInputConsumerController);
         mTouchHandler = new PipTouchHandler(context, mActivityManager,
                 mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
-                floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState);
+                floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState,
+                pipUiEventLogger);
         mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
                 mTouchHandler.getMotionHelper());
         displayController.addDisplayChangingController(mRotationController);
@@ -318,7 +323,7 @@
      */
     @Override
     public void expandPip() {
-        mTouchHandler.getMotionHelper().expandPipToFullscreen(false /* skipAnimation */);
+        mTouchHandler.getMotionHelper().expandLeavePip(false /* skipAnimation */);
     }
 
     /**
@@ -371,10 +376,10 @@
     }
 
     @Override
-    public void onPipTransitionStarted(ComponentName activity, int direction) {
+    public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
         if (isOutPipDirection(direction)) {
             // Exiting PIP, save the reentry bounds to restore to when re-entering.
-            updateReentryBounds();
+            updateReentryBounds(pipBounds);
             mPipBoundsHandler.onSaveReentryBounds(activity, mReentryBounds);
         }
         // Disable touches while the animation is running
@@ -391,15 +396,8 @@
     /**
      * Update the bounds used to save the re-entry size and snap fraction when exiting PIP.
      */
-    public void updateReentryBounds() {
-        // On phones, the expansion animation that happens on pip tap before restoring
-        // to fullscreen makes it so that the last reported bounds are the expanded
-        // bounds. We want to restore to the unexpanded bounds when re-entering pip,
-        // so we use the bounds before expansion (normal) instead of the reported
-        // bounds.
-        Rect reentryBounds = mTouchHandler.getNormalBounds();
-        // Apply the snap fraction of the current bounds to the normal bounds.
-        final Rect bounds = mPipTaskOrganizer.getLastReportedBounds();
+    public void updateReentryBounds(Rect bounds) {
+        final Rect reentryBounds = mTouchHandler.getUserResizeBounds();
         float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
         mPipBoundsHandler.applySnapFraction(reentryBounds, snapFraction);
         mReentryBounds.set(reentryBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index d6f3e16..1b1b2de 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -76,17 +76,15 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.Interpolators;
-import com.android.systemui.SystemUIFactory;
 import com.android.wm.shell.R;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import javax.inject.Inject;
-
 /**
  * Translucent activity that gets started on top of a task in PIP to allow the user to control it.
+ * TODO(b/150319024): PipMenuActivity will move to a Window
  */
 public class PipMenuActivity extends Activity {
 
@@ -126,19 +124,11 @@
     private final List<RemoteAction> mActions = new ArrayList<>();
 
     private AccessibilityManager mAccessibilityManager;
-    private View mViewRoot;
     private Drawable mBackgroundDrawable;
     private View mMenuContainer;
     private LinearLayout mActionsGroup;
-    private View mSettingsButton;
-    private View mDismissButton;
-    private View mResizeHandle;
-    private View mTopEndContainer;
     private int mBetweenActionPaddingLand;
 
-    @Inject
-    PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
-
     private AnimatorSet mMenuContainerAnimator;
 
     private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
@@ -193,6 +183,9 @@
                     break;
                 }
                 case MESSAGE_MENU_EXPANDED : {
+                    if (mMenuContainerAnimator == null) {
+                        return;
+                    }
                     mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
                     mMenuContainerAnimator.start();
                     break;
@@ -202,6 +195,9 @@
                     break;
                 }
                 case MESSAGE_UPDATE_MENU_LAYOUT: {
+                    if (mPipMenuIconsAlgorithm == null) {
+                        return;
+                    }
                     final Rect bounds = (Rect) msg.obj;
                     mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
                     break;
@@ -214,6 +210,13 @@
 
     private final Runnable mFinishRunnable = this::hideMenu;
 
+    protected View mViewRoot;
+    protected View mSettingsButton;
+    protected View mDismissButton;
+    protected View mResizeHandle;
+    protected View mTopEndContainer;
+    protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
+
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         // Set the flags to allow us to watch for outside touches and also hide the menu and start
@@ -222,8 +225,6 @@
 
         super.onCreate(savedInstanceState);
 
-        SystemUIFactory.getInstance().getRootComponent().inject(this);
-
         setContentView(R.layout.pip_menu_activity);
 
         mAccessibilityManager = getSystemService(AccessibilityManager.class);
@@ -254,7 +255,7 @@
         mActionsGroup = findViewById(R.id.actions_group);
         mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
                 R.dimen.pip_between_action_padding_land);
-
+        mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(this.getApplicationContext());
         mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
                 mResizeHandle, mSettingsButton, mDismissButton);
         updateFromIntent(getIntent());
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 267c5ea..383f6b3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -110,6 +110,8 @@
         void onPipShowMenu();
     }
 
+    /** TODO(b/150319024): PipMenuActivity will move to a Window */
+    private Class<?> mPipMenuActivityClass;
     private Context mContext;
     private PipMediaController mMediaController;
     private InputConsumerController mInputConsumerController;
@@ -185,11 +187,13 @@
         }
     };
 
-    public PipMenuActivityController(Context context,
-            PipMediaController mediaController, InputConsumerController inputConsumerController) {
+    public PipMenuActivityController(Context context, Class<?> pipMenuActivityClass,
+            PipMediaController mediaController, InputConsumerController inputConsumerController
+    ) {
         mContext = context;
         mMediaController = mediaController;
         mInputConsumerController = inputConsumerController;
+        mPipMenuActivityClass = pipMenuActivityClass;
     }
 
     public boolean isMenuActivityVisible() {
@@ -454,7 +458,7 @@
                     WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
             if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
                     pinnedStackInfo.taskIds.length > 0) {
-                Intent intent = new Intent(mContext, PipMenuActivity.class);
+                Intent intent = new Intent(mContext, mPipMenuActivityClass);
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
                 intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
index 69a04d8..6cfed07 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuIconsAlgorithm.java
@@ -24,8 +24,6 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
-import javax.inject.Inject;
-
 /**
  * Helper class to calculate and place the menu icons on the PIP Menu.
  */
@@ -40,8 +38,7 @@
     protected View mSettingsButton;
     protected View mDismissButton;
 
-    @Inject
-    public PipMenuIconsAlgorithm(Context context) {
+    protected PipMenuIconsAlgorithm(Context context) {
     }
 
     /**
@@ -56,7 +53,6 @@
         mDismissButton = dismissButton;
     }
 
-
     /**
      * Updates the position of the drag handle based on where the PIP window is on the screen.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index ca3ef24..19138fdb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -54,7 +54,7 @@
 
     private static final int SHRINK_STACK_FROM_MENU_DURATION = 250;
     private static final int EXPAND_STACK_TO_MENU_DURATION = 250;
-    private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 300;
+    private static final int LEAVE_PIP_DURATION = 300;
     private static final int SHIFT_DURATION = 300;
 
     /** Friction to use for PIP when it moves via physics fling animations. */
@@ -154,7 +154,7 @@
     private final PipTaskOrganizer.PipTransitionCallback mPipTransitionCallback =
             new PipTaskOrganizer.PipTransitionCallback() {
         @Override
-        public void onPipTransitionStarted(ComponentName activity, int direction) {}
+        public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {}
 
         @Override
         public void onPipTransitionFinished(ComponentName activity, int direction) {
@@ -304,16 +304,18 @@
     }
 
     /**
-     * Resizes the pinned stack back to fullscreen.
+     * Resizes the pinned stack back to unknown windowing mode, which could be freeform or
+     *      * fullscreen depending on the display area's windowing mode.
      */
-    void expandPipToFullscreen() {
-        expandPipToFullscreen(false /* skipAnimation */);
+    void expandLeavePip() {
+        expandLeavePip(false /* skipAnimation */);
     }
 
     /**
-     * Resizes the pinned stack back to fullscreen.
+     * Resizes the pinned stack back to unknown windowing mode, which could be freeform or
+     * fullscreen depending on the display area's windowing mode.
      */
-    void expandPipToFullscreen(boolean skipAnimation) {
+    void expandLeavePip(boolean skipAnimation) {
         if (DEBUG) {
             Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
                     + " callers=\n" + Debug.getCallers(5, "    "));
@@ -323,7 +325,7 @@
         mPipTaskOrganizer.getUpdateHandler().post(() -> {
             mPipTaskOrganizer.exitPip(skipAnimation
                     ? 0
-                    : EXPAND_STACK_TO_FULLSCREEN_DURATION);
+                    : LEAVE_PIP_DURATION);
         });
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index d884fa9..9c42f8b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -52,6 +52,7 @@
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.wm.shell.R;
 
@@ -88,6 +89,7 @@
     private final Point mMaxSize = new Point();
     private final Point mMinSize = new Point();
     private final Rect mLastResizeBounds = new Rect();
+    private final Rect mUserResizeBounds = new Rect();
     private final Rect mLastDownBounds = new Rect();
     private final Rect mDragCornerSize = new Rect();
     private final Rect mTmpTopLeftCorner = new Rect();
@@ -109,13 +111,15 @@
     private InputMonitor mInputMonitor;
     private InputEventReceiver mInputEventReceiver;
     private PipTaskOrganizer mPipTaskOrganizer;
+    private PipUiEventLogger mPipUiEventLogger;
 
     private int mCtrlType;
 
     public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
             PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
             PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
-            Runnable updateMovementBoundsRunnable, SysUiState sysUiState) {
+            Runnable updateMovementBoundsRunnable, SysUiState sysUiState,
+            PipUiEventLogger pipUiEventLogger) {
         mContext = context;
         mDisplayId = context.getDisplayId();
         mMainExecutor = context.getMainExecutor();
@@ -125,6 +129,7 @@
         mMovementBoundsSupplier = movementBoundsSupplier;
         mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
         mSysUiState = sysUiState;
+        mPipUiEventLogger = pipUiEventLogger;
 
         context.getDisplay().getRealSize(mMaxSize);
         reloadResources();
@@ -181,6 +186,7 @@
 
     void onActivityUnpinned() {
         mIsAttached = false;
+        mUserResizeBounds.setEmpty();
         updateIsEnabled();
     }
 
@@ -329,6 +335,7 @@
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
                     if (!mLastResizeBounds.isEmpty()) {
+                        mUserResizeBounds.set(mLastResizeBounds);
                         mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
                                 (Rect bounds) -> {
                                     new Handler(Looper.getMainLooper()).post(() -> {
@@ -337,6 +344,8 @@
                                         resetState();
                                     });
                                 });
+                        mPipUiEventLogger.log(
+                                PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE);
                     } else {
                         resetState();
                     }
@@ -351,6 +360,14 @@
         mThresholdCrossed = false;
     }
 
+    void setUserResizeBounds(Rect bounds) {
+        mUserResizeBounds.set(bounds);
+    }
+
+    Rect getUserResizeBounds() {
+        return mUserResizeBounds;
+    }
+
     void updateMaxSize(int maxX, int maxY) {
         mMaxSize.set(maxX, maxY);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 5434b62..b20ea4e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -34,7 +34,6 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Size;
 import android.view.Gravity;
 import android.view.IPinnedStackController;
@@ -55,13 +54,13 @@
 import androidx.dynamicanimation.animation.SpringForce;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.systemui.R;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipAnimationController;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DismissCircleView;
@@ -94,6 +93,8 @@
     private final WindowManager mWindowManager;
     private final IActivityManager mActivityManager;
     private final PipBoundsHandler mPipBoundsHandler;
+    private final PipUiEventLogger mPipUiEventLogger;
+
     private PipResizeGestureHandler mPipResizeGestureHandler;
     private IPinnedStackController mPinnedStackController;
 
@@ -132,9 +133,6 @@
 
     // The current movement bounds
     private Rect mMovementBounds = new Rect();
-    // The current resized bounds, changed by user resize.
-    // This is used during expand/un-expand to save/restore the user's resized size.
-    @VisibleForTesting Rect mResizedBounds = new Rect();
 
     // The reference inset bounds, used to determine the dismiss fraction
     private Rect mInsetBounds = new Rect();
@@ -193,16 +191,12 @@
 
         @Override
         public void onPipExpand() {
-            mMotionHelper.expandPipToFullscreen();
+            mMotionHelper.expandLeavePip();
         }
 
         @Override
         public void onPipDismiss() {
-            Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
-                    mActivityManager);
-            if (topPipActivity.first != null) {
-                MetricsLoggerWrapper.logPictureInPictureDismissByTap(mContext, topPipActivity);
-            }
+            mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_TAP_TO_REMOVE);
             mTouchState.removeDoubleTapTimeoutCallback();
             mMotionHelper.dismissPip();
         }
@@ -223,7 +217,8 @@
             FloatingContentCoordinator floatingContentCoordinator,
             DeviceConfigProxy deviceConfig,
             PipSnapAlgorithm pipSnapAlgorithm,
-            SysUiState sysUiState) {
+            SysUiState sysUiState,
+            PipUiEventLogger pipUiEventLogger) {
         // Initialize the Pip input consumer
         mContext = context;
         mActivityManager = activityManager;
@@ -238,7 +233,7 @@
         mPipResizeGestureHandler =
                 new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
                         deviceConfig, pipTaskOrganizer, this::getMovementBounds,
-                        this::updateMovementBounds, sysUiState);
+                        this::updateMovementBounds, sysUiState, pipUiEventLogger);
         mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
                 () -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
                         true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()),
@@ -259,6 +254,8 @@
                 pipTaskOrganizer, pipSnapAlgorithm, this::onAccessibilityShowMenu,
                 this::updateMovementBounds, mHandler);
 
+        mPipUiEventLogger = pipUiEventLogger;
+
         mTargetView = new DismissCircleView(context);
         mTargetViewContainer = new FrameLayout(context);
         mTargetViewContainer.setBackgroundDrawable(
@@ -307,11 +304,8 @@
                     hideDismissTarget();
                 });
 
-                Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
-                        mActivityManager);
-                if (topPipActivity.first != null) {
-                    MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext, topPipActivity);
-                }
+                mPipUiEventLogger.log(
+                        PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
             }
         });
 
@@ -383,7 +377,6 @@
 
             mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
         }
-        mResizedBounds.setEmpty();
         mPipResizeGestureHandler.onActivityUnpinned();
     }
 
@@ -393,9 +386,8 @@
         mMotionHelper.synchronizePinnedStackBounds();
         updateMovementBounds();
         if (direction == TRANSITION_DIRECTION_TO_PIP) {
-            // updates mResizedBounds only if it's an entering PiP animation
-            // mResized should be otherwise updated in setMenuState.
-            mResizedBounds.set(mMotionHelper.getBounds());
+            // Set the initial bounds as the user resize bounds.
+            mPipResizeGestureHandler.setUserResizeBounds(mMotionHelper.getBounds());
         }
 
         if (mShowPipMenuOnAnimationEnd) {
@@ -808,9 +800,7 @@
             // Save the current snap fraction and if we do not drag or move the PiP, then
             // we store back to this snap fraction.  Otherwise, we'll reset the snap
             // fraction and snap to the closest edge.
-            // Also save the current resized bounds so when the menu disappears, we can restore it.
             if (resize) {
-                mResizedBounds.set(mMotionHelper.getBounds());
                 Rect expandedBounds = new Rect(mExpandedBounds);
                 mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
                         mMovementBounds, mExpandedMovementBounds, callback);
@@ -839,7 +829,7 @@
                 }
 
                 if (mDeferResizeToNormalBoundsUntilRotation == -1) {
-                    Rect restoreBounds = new Rect(mResizedBounds);
+                    Rect restoreBounds = new Rect(getUserResizeBounds());
                     Rect restoredMovementBounds = new Rect();
                     mSnapAlgorithm.getMovementBounds(restoreBounds, mInsetBounds,
                             restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
@@ -856,8 +846,10 @@
         // If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
         // as well, or it can't handle a11y focus and pip menu can't perform any action.
         onRegistrationChanged(menuState == MENU_STATE_NONE);
-        if (menuState != MENU_STATE_CLOSE) {
-            MetricsLoggerWrapper.logPictureInPictureMenuVisible(mContext, menuState == MENU_STATE_FULL);
+        if (menuState == MENU_STATE_NONE) {
+            mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_HIDE_MENU);
+        } else if (menuState == MENU_STATE_FULL) {
+            mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_SHOW_MENU);
         }
     }
 
@@ -890,6 +882,10 @@
         return mNormalBounds;
     }
 
+    Rect getUserResizeBounds() {
+        return mPipResizeGestureHandler.getUserResizeBounds();
+    }
+
     /**
      * Gesture controlling normal movement of the PIP.
      */
@@ -991,7 +987,7 @@
                 // Expand to fullscreen if this is a double tap
                 // the PiP should be frozen until the transition ends
                 setTouchEnabled(false);
-                mMotionHelper.expandPipToFullscreen();
+                mMotionHelper.expandLeavePip();
             } else if (mMenuState != MENU_STATE_FULL) {
                 if (!mTouchState.isWaitingForDoubleTap()) {
                     // User has stalled long enough for this not to be a drag or a double tap, just
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
similarity index 61%
copy from tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
copy to packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
index 41036ab..114c30e 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 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,13 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.testing.dummyime;
+package com.android.systemui.pip.phone.dagger;
 
-import android.preference.PreferenceActivity;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
-/**
- * Dummy IME preference activity
- */
-public class ImePreferences extends PreferenceActivity {
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
 
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface PipMenuActivityClass {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 2138f09..0167028 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -663,7 +663,7 @@
     };
 
     @Override
-    public void onPipTransitionStarted(ComponentName activity, int direction) { }
+    public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { }
 
     @Override
     public void onPipTransitionFinished(ComponentName activity, int direction) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 560998b..22c735d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -185,7 +185,9 @@
             fakeDragBy(getScrollX() - mScroller.getCurrX());
         } else if (isFakeDragging()) {
             endFakeDrag();
-            mBounceAnimatorSet.start();
+            if (mBounceAnimatorSet != null) {
+                mBounceAnimatorSet.start();
+            }
             setOffscreenPageLimit(1);
         }
         super.computeScroll();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 8c485a6..d2aaaede 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -451,15 +451,17 @@
         if (listening) {
             if (mListeners.add(listener) && mListeners.size() == 1) {
                 if (DEBUG) Log.d(TAG, "handleSetListening true");
-                mLifecycle.setCurrentState(RESUMED);
                 handleSetListening(listening);
-                refreshState(); // Ensure we get at least one refresh after listening.
+                mUiHandler.post(() -> {
+                    mLifecycle.setCurrentState(RESUMED);
+                    refreshState(); // Ensure we get at least one refresh after listening.
+                });
             }
         } else {
             if (mListeners.remove(listener) && mListeners.size() == 0) {
                 if (DEBUG) Log.d(TAG, "handleSetListening false");
-                mLifecycle.setCurrentState(STARTED);
                 handleSetListening(listening);
+                mUiHandler.post(() -> mLifecycle.setCurrentState(STARTED));
             }
         }
         updateIsFullQs();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 5f37cc45..df61fd1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -65,10 +65,6 @@
         }
     }
 
-    public void growRecents() {
-        mImpl.growRecents();
-    }
-
     @Override
     public void showRecentApps(boolean triggeredFromAltTab) {
         // Ensure the device has been provisioned before allowing the user to interact with
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
index 6f5ceab..6d1299b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
@@ -205,7 +205,8 @@
         mPublicNotificationBuilder
                 .setContentTitle(mResources.getString(R.string.screenshot_saved_title))
                 .setContentText(mResources.getString(R.string.screenshot_saved_text))
-                .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
+                .setContentIntent(PendingIntent
+                        .getActivity(mContext, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE))
                 .setWhen(now)
                 .setAutoCancel(true)
                 .setColor(mContext.getColor(
@@ -213,7 +214,8 @@
         mNotificationBuilder
                 .setContentTitle(mResources.getString(R.string.screenshot_saved_title))
                 .setContentText(mResources.getString(R.string.screenshot_saved_text))
-                .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
+                .setContentIntent(PendingIntent
+                        .getActivity(mContext, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE))
                 .setWhen(now)
                 .setAutoCancel(true)
                 .setColor(mContext.getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 5301bbd..4007abb 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -23,20 +23,16 @@
 import android.window.WindowContainerToken;
 
 import com.android.systemui.SystemUI;
-import com.android.systemui.recents.Recents;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Optional;
 import java.util.function.Consumer;
 
 import javax.inject.Singleton;
 
-import dagger.Lazy;
-
 /**
  * Controls the docked stack divider.
  */
@@ -44,15 +40,12 @@
 public class Divider extends SystemUI {
     private final KeyguardStateController mKeyguardStateController;
     private final DividerController mDividerController;
-    private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
 
     Divider(Context context, DividerController dividerController,
-            KeyguardStateController keyguardStateController,
-            Optional<Lazy<Recents>> recentsOptionalLazy) {
+            KeyguardStateController keyguardStateController) {
         super(context);
         mDividerController = dividerController;
         mKeyguardStateController = keyguardStateController;
-        mRecentsOptionalLazy = recentsOptionalLazy;
     }
 
     @Override
@@ -113,8 +106,7 @@
     }
 
     public void onRecentsDrawn() {
-        mDividerController.onRecentsDrawn(() -> mRecentsOptionalLazy.ifPresent(
-                recentsLazy -> recentsLazy.get().growRecents()));
+        mDividerController.onRecentsDrawn();
     }
 
     public void onDockedFirstAnimationFrame() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
index 14fc157..81649f6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
@@ -391,9 +391,9 @@
      * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
      * register the event handler here and proxy the event to the current DividerView.
      */
-    public void onRecentsDrawn(DividerView.RecentDrawnCallback callback) {
+    public void onRecentsDrawn() {
         if (mView != null) {
-            mView.onRecentsDrawn(callback);
+            mView.onRecentsDrawn();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
index cdf44d7..db0aef8 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
@@ -20,18 +20,14 @@
 import android.os.Handler;
 
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.recents.Recents;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.SystemWindows;
 import com.android.wm.shell.common.TransactionPool;
 
-import java.util.Optional;
-
 import javax.inject.Singleton;
 
-import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
@@ -42,14 +38,12 @@
 public class DividerModule {
     @Singleton
     @Provides
-    static Divider provideDivider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
-            DisplayController displayController, SystemWindows systemWindows,
-            DisplayImeController imeController, @Main Handler handler,
+    static Divider provideDivider(Context context, DisplayController displayController,
+            SystemWindows systemWindows, DisplayImeController imeController, @Main Handler handler,
             KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
         // TODO(b/161116823): fetch DividerProxy from WM shell lib.
         DividerController dividerController = new DividerController(context, displayController,
                 systemWindows, imeController, handler, transactionPool);
-        return new Divider(context, dividerController, keyguardStateController,
-                recentsOptionalLazy);
+        return new Divider(context, dividerController, keyguardStateController);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
index 3a5c61e..8e79d51 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
@@ -21,6 +21,5 @@
  */
 public class DividerState {
     public boolean animateAfterRecentsDrawn;
-    public boolean growAfterRecentsDrawn;
     public float mRatioPositionBeforeMinimized;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 6447c52..e5c02d6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -83,10 +83,6 @@
         void onDraggingEnd();
     }
 
-    interface RecentDrawnCallback {
-        void growRecents();
-    }
-
     static final long TOUCH_ANIMATION_DURATION = 150;
     static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
 
@@ -151,7 +147,6 @@
     private DividerCallbacks mCallback;
     private final AnimationHandler mAnimationHandler = new AnimationHandler();
 
-    private boolean mGrowRecents;
     private ValueAnimator mCurrentAnimator;
     private boolean mEntranceAnimationRunning;
     private boolean mExitAnimationRunning;
@@ -307,7 +302,6 @@
                 R.dimen.docked_stack_divider_lift_elevation);
         mLongPressEntraceAnimDuration = getResources().getInteger(
                 R.integer.long_press_dock_anim_duration);
-        mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
         mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
         boolean landscape = getResources().getConfiguration().orientation
@@ -1322,39 +1316,11 @@
                 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
     }
 
-    /**
-     * Checks whether recents will grow when invoked. This happens in multi-window when recents is
-     * very small. When invoking recents, we shrink the docked stack so recents has more space.
-     *
-     * @return the position of the divider when recents grows, or
-     *         {@link #INVALID_RECENTS_GROW_TARGET} if recents won't grow
-     */
-    public int growsRecents() {
-        boolean result = mGrowRecents
-                && mDockSide == WindowManager.DOCKED_TOP
-                && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
-        if (result) {
-            return getSnapAlgorithm().getMiddleTarget().position;
-        } else {
-            return INVALID_RECENTS_GROW_TARGET;
-        }
-    }
-
-    void onRecentsActivityStarting() {
-        if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP
-                && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
-                && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
-            mState.growAfterRecentsDrawn = true;
-            startDragging(false /* animate */, false /* touching */);
-        }
-    }
-
     void onDockedFirstAnimationFrame() {
         saveSnapTargetBeforeMinimized(mSplitLayout.getSnapAlgorithm().getMiddleTarget());
     }
 
     void onDockedTopTask() {
-        mState.growAfterRecentsDrawn = false;
         mState.animateAfterRecentsDrawn = true;
         startDragging(false /* animate */, false /* touching */);
         updateDockSide();
@@ -1366,7 +1332,7 @@
                 null /* transaction */);
     }
 
-    void onRecentsDrawn(RecentDrawnCallback callback) {
+    void onRecentsDrawn() {
         updateDockSide();
         final int position = calculatePositionForInsetBounds();
         if (mState.animateAfterRecentsDrawn) {
@@ -1380,15 +1346,6 @@
                         200 /* endDelay */);
             });
         }
-        if (mState.growAfterRecentsDrawn) {
-            mState.growAfterRecentsDrawn = false;
-            updateDockSide();
-            if (callback != null) {
-                callback.growRecents();
-            }
-            stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336,
-                    Interpolators.FAST_OUT_SLOW_IN);
-        }
     }
 
     void onUndockingTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
index ca0f62e..b813b62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
@@ -20,9 +20,16 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.provider.Settings;
 
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import javax.inject.Inject;
@@ -35,23 +42,42 @@
  * should show an indicator.
  */
 @Singleton
-public class AssistantFeedbackController {
+public class AssistantFeedbackController extends ContentObserver {
+    private final Uri FEEDBACK_URI
+            = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_FEEDBACK_ENABLED);
     private ContentResolver mResolver;
 
+    private boolean mFeedbackEnabled;
+
     /** Injected constructor */
     @Inject
     public AssistantFeedbackController(Context context) {
+        super(new Handler(Looper.getMainLooper()));
         mResolver = context.getContentResolver();
+        mResolver.registerContentObserver(FEEDBACK_URI, false, this, UserHandle.USER_ALL);
+        update(null);
+    }
+
+    @Override
+    public void onChange(boolean selfChange, @Nullable Uri uri, int flags) {
+        update(uri);
+    }
+
+    @VisibleForTesting
+    public void update(@Nullable Uri uri) {
+        if (uri == null || FEEDBACK_URI.equals(uri)) {
+            mFeedbackEnabled = Settings.Global.getInt(mResolver,
+                    Settings.Global.NOTIFICATION_FEEDBACK_ENABLED, 0)
+                    != 0;
+        }
     }
 
     /**
      * Determines whether to show any user controls related to the assistant. This is based on the
-     * settings flag {@link Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED}
+     * settings flag {@link Settings.Global.NOTIFICATION_FEEDBACK_ENABLED}
      */
     public boolean isFeedbackEnabled() {
-        return Settings.Secure.getIntForUser(mResolver,
-                Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED, 0,
-                UserHandle.USER_CURRENT) == 1;
+        return mFeedbackEnabled;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index b773856..95ba759 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -64,6 +64,8 @@
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final HighPriorityProvider mHighPriorityProvider;
 
+    private boolean mHideSilentNotificationsOnLockscreen;
+
     @Inject
     public KeyguardCoordinator(
             Context context,
@@ -86,6 +88,8 @@
 
     @Override
     public void attach(NotifPipeline pipeline) {
+        readShowSilentNotificationSetting();
+
         setupInvalidateNotifListCallbacks();
         pipeline.addFinalizeFilter(mNotifFilter);
     }
@@ -147,7 +151,7 @@
             return false;
         }
         if (NotificationUtils.useNewInterruptionModel(mContext)
-                && hideSilentNotificationsOnLockscreen()) {
+                && mHideSilentNotificationsOnLockscreen) {
             return mHighPriorityProvider.isHighPriority(entry);
         } else {
             return entry.getRepresentativeEntry() != null
@@ -155,11 +159,6 @@
         }
     }
 
-    private boolean hideSilentNotificationsOnLockscreen() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0;
-    }
-
     private void setupInvalidateNotifListCallbacks() {
         // register onKeyguardShowing callback
         mKeyguardStateController.addCallback(mKeyguardCallback);
@@ -169,6 +168,11 @@
         final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
             @Override
             public void onChange(boolean selfChange, Uri uri) {
+                if (uri.equals(Settings.Secure.getUriFor(
+                        Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS))) {
+                    readShowSilentNotificationSetting();
+                }
+
                 if (mKeyguardStateController.isShowing()) {
                     invalidateListFromFilter("Settings " + uri + " changed");
                 }
@@ -192,6 +196,12 @@
                 false,
                 settingsObserver);
 
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
+                false,
+                settingsObserver,
+                UserHandle.USER_ALL);
+
         // register (maybe) public mode changed callbacks:
         mStatusBarStateController.addCallback(mStatusBarStateListener);
         mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
@@ -208,6 +218,14 @@
         mNotifFilter.invalidateList();
     }
 
+    private void readShowSilentNotificationSetting() {
+        mHideSilentNotificationsOnLockscreen =
+                Settings.Secure.getInt(
+                        mContext.getContentResolver(),
+                        Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
+                        1) == 0;
+    }
+
     private final KeyguardStateController.Callback mKeyguardCallback =
             new KeyguardStateController.Callback() {
         @Override
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 99cb476..a87311a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -2620,6 +2620,7 @@
         super.onClosingFinished();
         resetHorizontalPanelPosition();
         setClosingWithAlphaFadeout(false);
+        mMediaHierarchyManager.closeGuts();
     }
 
     private void setClosingWithAlphaFadeout(boolean closing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index e942d85..ac329e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -408,7 +408,7 @@
                 && !mKeyguardStateController.isKeyguardFadingAway()) {
             long timePassed = SystemClock.uptimeMillis() - mDownTime;
             if (timePassed < ViewConfiguration.getLongPressTimeout()) {
-                // Lets show the user that he can actually expand the panel
+                // Let's show the user that they can actually expand the panel
                 runPeekAnimation(
                         PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index d30f01a..88a6263 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -74,7 +74,7 @@
     protected boolean mPowerSave;
     private boolean mAodPowerSave;
     protected boolean mWirelessCharging;
-    private boolean mTestmode = false;
+    private boolean mTestMode = false;
     @VisibleForTesting
     boolean mHasReceivedBattery = false;
     private Estimate mEstimate;
@@ -154,7 +154,7 @@
     public void onReceive(final Context context, Intent intent) {
         final String action = intent.getAction();
         if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-            if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
+            if (mTestMode && !intent.getBooleanExtra("testmode", false)) return;
             mHasReceivedBattery = true;
             mLevel = (int)(100f
                     * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
@@ -172,29 +172,29 @@
         } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
             updatePowerSave();
         } else if (action.equals(ACTION_LEVEL_TEST)) {
-            mTestmode = true;
+            mTestMode = true;
             mMainHandler.post(new Runnable() {
                 int curLevel = 0;
                 int incr = 1;
                 int saveLevel = mLevel;
                 boolean savePlugged = mPluggedIn;
-                Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
+                Intent mTestIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
                 @Override
                 public void run() {
                     if (curLevel < 0) {
-                        mTestmode = false;
-                        dummy.putExtra("level", saveLevel);
-                        dummy.putExtra("plugged", savePlugged);
-                        dummy.putExtra("testmode", false);
+                        mTestMode = false;
+                        mTestIntent.putExtra("level", saveLevel);
+                        mTestIntent.putExtra("plugged", savePlugged);
+                        mTestIntent.putExtra("testmode", false);
                     } else {
-                        dummy.putExtra("level", curLevel);
-                        dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
+                        mTestIntent.putExtra("level", curLevel);
+                        mTestIntent.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
                                 : 0);
-                        dummy.putExtra("testmode", true);
+                        mTestIntent.putExtra("testmode", true);
                     }
-                    context.sendBroadcast(dummy);
+                    context.sendBroadcast(mTestIntent);
 
-                    if (!mTestmode) return;
+                    if (!mTestMode) return;
 
                     curLevel += incr;
                     if (curLevel == 100) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
index b25df5f..5e72808 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
@@ -104,9 +104,13 @@
                     .setContentText(String.format(
                             "SystemUI has detected %d leaked objects. Tap to send", garbageCount))
                     .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                    .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+                    .setContentIntent(PendingIntent.getActivityAsUser(
+                            mContext,
+                            0,
                             getIntent(hprofFile, dumpFile),
-                            PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT));
+                            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+                            null,
+                            UserHandle.CURRENT));
             notiMan.notify(TAG, 0, builder.build());
         } catch (IOException e) {
             Log.e(TAG, "Couldn't dump heap for leak", e);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 9fa03df..06806d0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -338,7 +338,7 @@
         @Override
         public void run() {
             unregister();
-            mSensor.alertListeners();
+            onProximityEvent(null);
         }
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
index 5b2c39d..d2c61cc 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
@@ -21,6 +21,8 @@
 import android.view.IWindowManager;
 
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.phone.PipMenuActivity;
+import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.SystemWindows;
@@ -65,4 +67,12 @@
         return new DisplayImeController.Builder(wmService, displayController, mainHandler,
                 transactionPool).build();
     }
+
+    /** TODO(b/150319024): PipMenuActivity will move to a Window */
+    @Singleton
+    @PipMenuActivityClass
+    @Provides
+    static Class<?> providePipMenuActivityClass() {
+        return PipMenuActivity.class;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
new file mode 100644
index 0000000..4d0f2ed
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls
+
+import android.content.ComponentName
+import android.graphics.drawable.Icon
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+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)
+class CustomIconCacheTest : SysuiTestCase() {
+
+    companion object {
+        private val TEST_COMPONENT1 = ComponentName.unflattenFromString("pkg/.cls1")!!
+        private val TEST_COMPONENT2 = ComponentName.unflattenFromString("pkg/.cls2")!!
+        private const val CONTROL_ID_1 = "TEST_CONTROL_1"
+        private const val CONTROL_ID_2 = "TEST_CONTROL_2"
+    }
+
+    @Mock(stubOnly = true)
+    private lateinit var icon1: Icon
+    @Mock(stubOnly = true)
+    private lateinit var icon2: Icon
+    private lateinit var customIconCache: CustomIconCache
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        customIconCache = CustomIconCache()
+    }
+
+    @Test
+    fun testIconStoredCorrectly() {
+        customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+        assertTrue(icon1 === customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+    }
+
+    @Test
+    fun testIconNotStoredReturnsNull() {
+        customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+        assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_2))
+    }
+
+    @Test
+    fun testWrongComponentReturnsNull() {
+        customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+        assertNull(customIconCache.retrieve(TEST_COMPONENT2, CONTROL_ID_1))
+    }
+
+    @Test
+    fun testChangeComponentOldComponentIsRemoved() {
+        customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+        customIconCache.store(TEST_COMPONENT2, CONTROL_ID_2, icon2)
+
+        assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+        assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_2))
+    }
+
+    @Test
+    fun testChangeComponentCorrectIconRetrieved() {
+        customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+        customIconCache.store(TEST_COMPONENT2, CONTROL_ID_1, icon2)
+
+        assertTrue(icon2 === customIconCache.retrieve(TEST_COMPONENT2, CONTROL_ID_1))
+    }
+
+    @Test
+    fun testStoreNull() {
+        customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+        customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, null)
+
+        assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
index ce33a8d..f0003ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
@@ -22,6 +22,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.CustomIconCache
 import com.android.systemui.controls.controller.ControlInfo
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
@@ -57,6 +58,8 @@
     private lateinit var callback: FavoritesModel.FavoritesModelCallback
     @Mock
     private lateinit var adapter: RecyclerView.Adapter<*>
+    @Mock
+    private lateinit var customIconCache: CustomIconCache
     private lateinit var model: FavoritesModel
     private lateinit var dividerWrapper: DividerWrapper
 
@@ -64,7 +67,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        model = FavoritesModel(TEST_COMPONENT, INITIAL_FAVORITES, callback)
+        model = FavoritesModel(customIconCache, TEST_COMPONENT, INITIAL_FAVORITES, callback)
         model.attachAdapter(adapter)
         dividerWrapper = model.elements.first { it is DividerWrapper } as DividerWrapper
     }
@@ -89,7 +92,7 @@
     @Test
     fun testInitialElements() {
         val expected = INITIAL_FAVORITES.map {
-            ControlInfoWrapper(TEST_COMPONENT, it, true)
+            ControlInfoWrapper(TEST_COMPONENT, it, true, customIconCache::retrieve)
         } + DividerWrapper()
         assertEquals(expected, model.elements)
     }
@@ -287,5 +290,13 @@
         verify(callback).onFirstChange()
     }
 
+    @Test
+    fun testCacheCalledWhenGettingCustomIcon() {
+        val wrapper = model.elements[0] as ControlInfoWrapper
+        wrapper.customIcon
+
+        verify(customIconCache).retrieve(TEST_COMPONENT, wrapper.controlId)
+    }
+
     private fun getDividerPosition(): Int = model.elements.indexOf(dividerWrapper)
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index ac8c671..4c54954 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -88,7 +88,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class GlobalActionsDialogTest extends SysuiTestCase {
     private GlobalActionsDialog mGlobalActionsDialog;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index c63781c..8a30b00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.media
 
+import android.content.Intent
 import android.content.res.ColorStateList
 import android.graphics.Color
 import android.graphics.drawable.GradientDrawable
@@ -23,6 +24,7 @@
 import android.media.MediaMetadata
 import android.media.session.MediaSession
 import android.media.session.PlaybackState
+import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
@@ -35,24 +37,31 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.LiveData
 import androidx.test.filters.SmallTest
-import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil
 import com.android.systemui.util.animation.TransitionLayout
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.any
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyLong
 import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
 
 private const val KEY = "TEST_KEY"
 private const val APP = "APP"
@@ -81,6 +90,8 @@
     @Mock private lateinit var seekBarViewModel: SeekBarViewModel
     @Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
     @Mock private lateinit var mediaViewController: MediaViewController
+    @Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
+    @Mock private lateinit var mediaDataManager: MediaDataManager
     @Mock private lateinit var expandedSet: ConstraintSet
     @Mock private lateinit var collapsedSet: ConstraintSet
     private lateinit var appIcon: ImageView
@@ -100,6 +111,9 @@
     private lateinit var action2: ImageButton
     private lateinit var action3: ImageButton
     private lateinit var action4: ImageButton
+    private lateinit var settings: View
+    private lateinit var cancel: View
+    private lateinit var dismiss: View
 
     private lateinit var session: MediaSession
     private val device = MediaDeviceData(true, null, DEVICE_NAME)
@@ -114,7 +128,7 @@
         whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
 
         player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
-                seekBarViewModel)
+                seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil)
         whenever(seekBarViewModel.progress).thenReturn(seekBarData)
 
         // Mock out a view holder for the player to attach to.
@@ -156,6 +170,12 @@
         whenever(holder.action3).thenReturn(action3)
         action4 = ImageButton(context)
         whenever(holder.action4).thenReturn(action4)
+        settings = View(context)
+        whenever(holder.settings).thenReturn(settings)
+        cancel = View(context)
+        whenever(holder.cancel).thenReturn(cancel)
+        dismiss = View(context)
+        whenever(holder.dismiss).thenReturn(dismiss)
 
         // Create media session
         val metadataBuilder = MediaMetadata.Builder().apply {
@@ -254,4 +274,79 @@
         assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
         assertThat(seamless.isEnabled()).isFalse()
     }
+
+    @Test
+    fun longClick_gutsClosed() {
+        player.attach(holder)
+        whenever(mediaViewController.isGutsVisible).thenReturn(false)
+
+        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+        verify(holder.player).setOnLongClickListener(captor.capture())
+
+        captor.value.onLongClick(holder.player)
+        verify(mediaViewController).openGuts()
+    }
+
+    @Test
+    fun longClick_gutsOpen() {
+        player.attach(holder)
+        whenever(mediaViewController.isGutsVisible).thenReturn(true)
+
+        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+        verify(holder.player).setOnLongClickListener(captor.capture())
+
+        captor.value.onLongClick(holder.player)
+        verify(mediaViewController, never()).openGuts()
+    }
+
+    @Test
+    fun cancelButtonClick_animation() {
+        player.attach(holder)
+
+        cancel.callOnClick()
+
+        verify(mediaViewController).closeGuts(false)
+    }
+
+    @Test
+    fun settingsButtonClick() {
+        player.attach(holder)
+
+        settings.callOnClick()
+
+        val captor = ArgumentCaptor.forClass(Intent::class.java)
+        verify(activityStarter).startActivity(captor.capture(), eq(true))
+
+        assertThat(captor.value.action).isEqualTo(ACTION_MEDIA_CONTROLS_SETTINGS)
+    }
+
+    @Test
+    fun dismissButtonClick() {
+        player.attach(holder)
+        val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+                emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null,
+                notificationKey = KEY)
+        player.bind(state)
+
+        dismiss.callOnClick()
+        val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java)
+        verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean())
+
+        captor.value.onDismiss()
+        verify(mediaDataManager).dismissMediaData(eq(KEY), anyLong())
+    }
+
+    @Test
+    fun dismissButtonClick_nullNotificationKey() {
+        player.attach(holder)
+        val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+                emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null)
+        player.bind(state)
+
+        verify(keyguardDismissUtil, never())
+                .executeWhenUnlocked(
+                        any(ActivityStarter.OnDismissAction::class.java),
+                        ArgumentMatchers.anyBoolean()
+                )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 59c2d0e..3789e6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -217,6 +217,20 @@
         assertThat(data.actions).hasSize(1)
     }
 
+    @Test
+    fun testDismissMedia_listenerCalled() {
+        val listener = mock(MediaDataManager.Listener::class.java)
+        mediaDataManager.addListener(listener)
+        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+        mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
+        mediaDataManager.dismissMediaData(KEY, 0L)
+
+        foregroundExecutor.advanceClockToLast()
+        foregroundExecutor.runAllReady()
+
+        verify(listener).onMediaDataRemoved(eq(KEY))
+    }
+
     /**
      * Simple implementation of [MediaDataManager.Listener] for the test.
      *
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 91c5ff8..d86dfa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -142,4 +142,11 @@
         verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
                 any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
     }
+
+    @Test
+    fun testCloseGutsRelayToCarousel() {
+        mediaHiearchyManager.closeGuts()
+
+        verify(mediaCarouselController).closeGuts()
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index c9c1111..f0066ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.pip;
 
-import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
 import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
 
 import static org.junit.Assert.assertEquals;
@@ -116,9 +116,9 @@
 
         animator = mPipAnimationController
                 .getAnimator(mLeash, new Rect(), 0f, 1f)
-                .setTransitionDirection(TRANSITION_DIRECTION_TO_FULLSCREEN);
+                .setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP);
         assertEquals("Transition to fullscreen mode",
-                animator.getTransitionDirection(), TRANSITION_DIRECTION_TO_FULLSCREEN);
+                animator.getTransitionDirection(), TRANSITION_DIRECTION_LEAVE_PIP);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
index 96bb521..9f67722 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
@@ -37,6 +37,7 @@
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.FloatingContentCoordinator;
@@ -85,6 +86,9 @@
     @Mock
     private SysUiState mSysUiState;
 
+    @Mock
+    private PipUiEventLogger mPipUiEventLogger;
+
     private PipSnapAlgorithm mPipSnapAlgorithm;
     private PipMotionHelper mMotionHelper;
     private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -104,7 +108,7 @@
         mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager,
                 mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
                 mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy,
-                mPipSnapAlgorithm, mSysUiState);
+                mPipSnapAlgorithm, mSysUiState, mPipUiEventLogger);
         mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
         mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
         mPipTouchHandler.setPipMotionHelper(mMotionHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 103e558..cccb65d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -74,7 +74,7 @@
 import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class QSTileImplTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 2d276bb..6b54791 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -47,7 +47,7 @@
 import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class ScreenRecordTileTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index 619d244..fb8c3d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -57,8 +57,8 @@
 
     @Before
     public void setUp() {
-        switchSetting(ON);
         mAssistantFeedbackController = new AssistantFeedbackController(mContext);
+        switchSetting(ON);
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
                 0, null, TEST_UID, 0, new Notification(),
                 UserHandle.CURRENT, null, 0);
@@ -72,7 +72,6 @@
 
     @Test
     public void testUserControls_settingEnabled() {
-        switchSetting(ON);
         assertTrue(mAssistantFeedbackController.isFeedbackEnabled());
     }
 
@@ -113,7 +112,8 @@
     }
 
     private void switchSetting(int setting) {
-        Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                Settings.Secure.NOTIFICATION_FEEDBACK_ENABLED, setting, UserHandle.USER_CURRENT);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.NOTIFICATION_FEEDBACK_ENABLED, setting);
+        mAssistantFeedbackController.update(null);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index ae87eef..781f875 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -41,7 +41,7 @@
 import org.mockito.Mockito;
 
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper()
+@RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
index a16fb5e..86dacc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
@@ -37,7 +37,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
 public class CallbackControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
index 0e1c560..b2f57d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
@@ -39,7 +39,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
 public class LifecycleFragmentTest extends SysuiBaseFragmentTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
index 486939d..4f509ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
@@ -49,7 +49,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
 public class SysuiLifecycleTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
index 8ba11da..c5a197e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.util.sensors;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -80,6 +81,8 @@
         mFakeExecutor.runAllReady();
 
         assertFalse(mFakeProximitySensor.isRegistered());
+        assertEquals(1, mTestableCallback.mNumCalls);
+        assertNull(mTestableCallback.mLastResult);
     }
 
     @Test
@@ -110,9 +113,12 @@
 
     private static class TestableCallback implements Consumer<Boolean> {
         Boolean mLastResult;
+        int mNumCalls = 0;
+
         @Override
         public void accept(Boolean result) {
             mLastResult = result;
+            mNumCalls++;
         }
     }
 }
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 9b9dcde..5f8d299 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -73,6 +73,9 @@
     <!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. -->
     <bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool>
 
+    <!-- Use legacy wifi p2p dedicated address instead of randomize address. -->
+    <bool translatable="false" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip">false</bool>
+
     <!-- Dhcp range (min, max) to use for tethering purposes -->
     <string-array translatable="false" name="config_tether_dhcp_range">
     </string-array>
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index 6a33d55..0ee7a99 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -30,6 +30,7 @@
             -->
             <item type="bool" name="config_tether_enable_bpf_offload"/>
             <item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
+            <item type="bool" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip"/>
             <item type="integer" name="config_tether_offload_poll_interval"/>
             <item type="array" name="config_tether_upstream_types"/>
             <item type="bool" name="config_tether_upstream_automatic"/>
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index aa58a4b..fd9e360 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,6 +15,8 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
 import static java.util.Arrays.asList;
 
 import android.content.Context;
@@ -58,6 +60,7 @@
     private static final int BYTE_MASK = 0xff;
     // reserved for bluetooth tethering.
     private static final int BLUETOOTH_RESERVED = 44;
+    private static final int WIFI_P2P_RESERVED = 49;
     private static final byte DEFAULT_ID = (byte) 42;
 
     // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
@@ -71,15 +74,18 @@
     // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
     // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
     private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
+    private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
     private final IpPrefix mTetheringPrefix;
     private final ConnectivityManager mConnectivityMgr;
+    private final TetheringConfiguration mConfig;
 
-    public PrivateAddressCoordinator(Context context) {
+    public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
         mDownstreams = new ArraySet<>();
         mUpstreamPrefixMap = new ArrayMap<>();
         mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX);
         mConnectivityMgr = (ConnectivityManager) context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
+        mConfig = config;
     }
 
     /**
@@ -141,12 +147,21 @@
         mUpstreamPrefixMap.removeAll(toBeRemoved);
     }
 
+    private boolean isReservedSubnet(final int subnet) {
+        return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED;
+    }
+
     /**
      * Pick a random available address and mark its prefix as in use for the provided IpServer,
      * returns null if there is no available address.
      */
     @Nullable
     public LinkAddress requestDownstreamAddress(final IpServer ipServer) {
+        if (mConfig.shouldEnableWifiP2pDedicatedIp()
+                && ipServer.interfaceType() == TETHERING_WIFI_P2P) {
+            return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
+        }
+
         // Address would be 192.168.[subAddress]/24.
         final byte[] bytes = mTetheringPrefix.getRawAddress();
         final int subAddress = getRandomSubAddr();
@@ -154,7 +169,7 @@
         bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
         for (int i = 0; i < MAX_UBYTE; i++) {
             final int newSubNet = (subNet + i) & BYTE_MASK;
-            if (newSubNet == BLUETOOTH_RESERVED) continue;
+            if (isReservedSubnet(newSubNet)) continue;
 
             bytes[2] = (byte) newSubNet;
             final InetAddress addr;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index cfc6575..7dd5290 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -320,10 +320,13 @@
         mExecutor = new TetheringThreadExecutor(mHandler);
         mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
         mNetdCallback = new NetdCallback();
-        mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext);
 
         // Load tethering configuration.
         updateConfiguration();
+        // It is OK for the configuration to be passed to the PrivateAddressCoordinator at
+        // construction time because the only part of the configuration it uses is
+        // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
+        mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig);
 
         // Must be initialized after tethering configuration is loaded because BpfCoordinator
         // constructor needs to use the configuration.
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index e1771a5..5783805 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -84,6 +84,9 @@
     public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
             "tether_enable_legacy_dhcp_server";
 
+    public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP =
+            "use_legacy_wifi_p2p_dedicated_ip";
+
     /**
      * Default value that used to periodic polls tether offload stats from tethering offload HAL
      * to make the data warnings work.
@@ -113,6 +116,7 @@
     private final int mOffloadPollInterval;
     // TODO: Add to TetheringConfigurationParcel if required.
     private final boolean mEnableBpfOffload;
+    private final boolean mEnableWifiP2pDedicatedIp;
 
     public TetheringConfiguration(Context ctx, SharedLog log, int id) {
         final SharedLog configLog = log.forSubComponent("config");
@@ -156,6 +160,10 @@
                 R.integer.config_tether_offload_poll_interval,
                 DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
 
+        mEnableWifiP2pDedicatedIp = getResourceBoolean(res,
+                R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip,
+                false /* defaultValue */);
+
         configLog.log(toString());
     }
 
@@ -199,6 +207,11 @@
         return !TextUtils.isEmpty(provisioningAppNoUi);
     }
 
+    /** Check whether dedicated wifi p2p address is enabled. */
+    public boolean shouldEnableWifiP2pDedicatedIp() {
+        return mEnableWifiP2pDedicatedIp;
+    }
+
     /** Does the dumping.*/
     public void dump(PrintWriter pw) {
         pw.print("activeDataSubId: ");
@@ -233,6 +246,9 @@
 
         pw.print("enableLegacyDhcpServer: ");
         pw.println(enableLegacyDhcpServer);
+
+        pw.print("enableWifiP2pDedicatedIp: ");
+        pw.println(mEnableWifiP2pDedicatedIp);
     }
 
     /** Returns the string representation of this object.*/
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 2c0df6f..8e93c2e 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,6 +15,11 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.Mockito.never;
@@ -54,22 +59,34 @@
     @Mock private IpServer mHotspotIpServer;
     @Mock private IpServer mUsbIpServer;
     @Mock private IpServer mEthernetIpServer;
+    @Mock private IpServer mWifiP2pIpServer;
     @Mock private Context mContext;
     @Mock private ConnectivityManager mConnectivityMgr;
+    @Mock private TetheringConfiguration mConfig;
 
     private PrivateAddressCoordinator mPrivateAddressCoordinator;
     private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24");
+    private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
     private final Network mWifiNetwork = new Network(1);
     private final Network mMobileNetwork = new Network(2);
     private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
 
+    private void setUpIpServers() throws Exception {
+        when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
+        when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET);
+        when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
+        when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P);
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr);
         when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks);
-        mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext));
+        when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false);
+        setUpIpServers();
+        mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
     }
 
     @Test
@@ -256,4 +273,38 @@
         final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr);
         assertEquals(predefinedPrefix, ethPrefix);
     }
+
+    private int getSubAddress(final byte... ipv4Address) {
+        assertEquals(4, ipv4Address.length);
+
+        int subnet = Byte.toUnsignedInt(ipv4Address[2]);
+        return (subnet << 8) + ipv4Address[3];
+    }
+
+    private void assertReseveredWifiP2pPrefix() throws Exception {
+        LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+                mHotspotIpServer);
+        final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
+        final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress);
+        assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
+        mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+    }
+
+    @Test
+    public void testEnableLegacyWifiP2PAddress() throws Exception {
+        when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+                getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
+        // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix
+        // is resevered.
+        assertReseveredWifiP2pPrefix();
+
+        when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(true);
+        assertReseveredWifiP2pPrefix();
+
+        // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
+        LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+                mWifiP2pIpServer);
+        assertEquals(mLegacyWifiP2pAddress, address);
+        mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
+    }
 }
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index a9ac4e2..dc0940c 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -128,6 +128,8 @@
                 .thenReturn(new String[0]);
         when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                 false);
+        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+                .thenReturn(false);
         initializeBpfOffloadConfiguration(true, null /* unset */);
 
         mHasTelephonyManager = true;
@@ -413,4 +415,17 @@
                 R.string.config_mobile_hotspot_provision_response)).thenReturn(
                 PROVISIONING_APP_RESPONSE);
     }
+
+    @Test
+    public void testEnableLegacyWifiP2PAddress() throws Exception {
+        final TetheringConfiguration defaultCfg = new TetheringConfiguration(
+                mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp());
+
+        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+                .thenReturn(true);
+        final TetheringConfiguration testCfg = new TetheringConfiguration(
+                mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp());
+    }
 }
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index b0e401b..3f712dd 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -3706,33 +3706,40 @@
     // OS: O
     BACKUP_SETTINGS = 818;
 
+    // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
     // ACTION: Picture-in-picture was explicitly entered for an activity
     // VALUE: true if it was entered while hiding as a result of moving to
     // another task, false otherwise
-    ACTION_PICTURE_IN_PICTURE_ENTERED = 819;
+    ACTION_PICTURE_IN_PICTURE_ENTERED = 819 [deprecated=true];
 
+    // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
     // ACTION: The activity currently in picture-in-picture was expanded back to fullscreen
     // PACKAGE: The package name of the activity that was expanded back to fullscreen
-    ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN = 820;
+    ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN = 820 [deprecated=true];
 
+    // DEPRECATED: The metrics no longer used after migration to UiEvent per go/uievent.
     // ACTION: The activity currently in picture-in-picture was minimized
     // VALUE: True if the PiP was minimized, false otherwise
-    ACTION_PICTURE_IN_PICTURE_MINIMIZED = 821;
+    ACTION_PICTURE_IN_PICTURE_MINIMIZED = 821 [deprecated=true];
 
+    // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
     // ACTION: Picture-in-picture was dismissed via the dismiss button
     // VALUE: 0 if dismissed by tap, 1 if dismissed by drag
-    ACTION_PICTURE_IN_PICTURE_DISMISSED = 822;
+    ACTION_PICTURE_IN_PICTURE_DISMISSED = 822 [deprecated=true];
 
-    // ACTION: The visibility of the picture-in-picture meny
+    // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
+    // ACTION: The visibility of the picture-in-picture menu
     // VALUE: Whether or not the menu is visible
-    ACTION_PICTURE_IN_PICTURE_MENU = 823;
+    ACTION_PICTURE_IN_PICTURE_MENU = 823 [deprecated=true];
 
+    // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
     // Enclosing category for group of PICTURE_IN_PICTURE_ASPECT_RATIO_FOO events,
     // logged when the aspect ratio changes
-    ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED = 824;
+    ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED = 824 [deprecated=true];
 
+    // DEPRECATED: The metrics no longer used after migration to UiEvent per go/uievent.
     // The current aspect ratio of the PiP, logged when it changes.
-    PICTURE_IN_PICTURE_ASPECT_RATIO = 825;
+    PICTURE_IN_PICTURE_ASPECT_RATIO = 825 [deprecated=true];
 
     // FIELD - length in dp of ACTION_LS_* gestures, or zero if not applicable
     // CATEGORY: GLOBAL_SYSTEM_UI
diff --git a/services/Android.bp b/services/Android.bp
index f0144ac..ef52c2a 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -30,6 +30,7 @@
         ":services.midi-sources",
         ":services.net-sources",
         ":services.print-sources",
+        ":services.profcollect-sources",
         ":services.restrictions-sources",
         ":services.startop.iorap-sources",
         ":services.systemcaptions-sources",
@@ -73,6 +74,7 @@
         "services.net",
         "services.people",
         "services.print",
+        "services.profcollect",
         "services.restrictions",
         "services.startop",
         "services.systemcaptions",
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 2cd4c69..b134022 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -443,7 +443,11 @@
                     if (reboundAService || configurationChanged) {
                         onUserStateChangedLocked(userState);
                     }
-                    migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName);
+                    // Passing 0 for restoreFromSdkInt to have this migration check execute each
+                    // time. It can make sure a11y button settings are correctly if there's an a11y
+                    // service updated and modifies the a11y button configuration.
+                    migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName,
+                            /* restoreFromSdkInt = */0);
                 }
             }
 
@@ -554,7 +558,9 @@
                         synchronized (mLock) {
                             restoreEnabledAccessibilityServicesLocked(
                                     intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
-                                    intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+                                    intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE),
+                                    intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
+                                            0));
                         }
                     } else if (ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(which)) {
                         synchronized (mLock) {
@@ -563,6 +569,12 @@
                                     intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
                                             0));
                         }
+                    } else if (Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS.equals(which)) {
+                        synchronized (mLock) {
+                            restoreAccessibilityButtonTargetsLocked(
+                                    intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
+                                    intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+                        }
                     }
                 }
             }
@@ -588,7 +600,7 @@
         final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
         final Set<String> targetsFromSetting = new ArraySet<>();
         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
-                userState.mUserId, targetsFromSetting, str -> str);
+                userState.mUserId, str -> str, targetsFromSetting);
         final boolean targetsContainMagnification = targetsFromSetting.contains(
                 MAGNIFICATION_CONTROLLER_NAME);
         if (targetsContainMagnification == displayMagnificationNavBarEnabled) {
@@ -1189,7 +1201,14 @@
             // the state since the context in which the current user
             // state was used has changed since it was inactive.
             onUserStateChangedLocked(userState);
-            migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null);
+            // It's better to have this migration in SettingsProvider. Unfortunately,
+            // SettingsProvider migrated database in a very early stage which A11yManagerService
+            // haven't finished or started the initialization. We cannot get enough information from
+            // A11yManagerService to execute these migrations in SettingsProvider. Passing 0 for
+            // restoreFromSdkInt to have this migration check execute every time, because we did not
+            // find out a way to detect the device finished the OTA and switch the user.
+            migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null,
+                    /* restoreFromSdkInt = */0);
 
             if (announceNewUser) {
                 // Schedule announcement of the current user if needed.
@@ -1234,7 +1253,8 @@
 
     // Called only during settings restore; currently supports only the owner user
     // TODO: http://b/22388012
-    void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting) {
+    void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting,
+            int restoreFromSdkInt) {
         readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
         readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
 
@@ -1246,7 +1266,32 @@
                 userState.mEnabledServices,
                 UserHandle.USER_SYSTEM);
         onUserStateChangedLocked(userState);
-        migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null);
+        migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, restoreFromSdkInt);
+    }
+
+    /**
+     * User could enable accessibility services and configure accessibility button during the SUW.
+     * Merges current value of accessibility button settings into the restored one to make sure
+     * user's preferences of accessibility button updated in SUW are not lost.
+     *
+     * Called only during settings restore; currently supports only the owner user
+     * TODO: http://b/22388012
+     */
+    void restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting) {
+        final Set<String> targetsFromSetting = new ArraySet<>();
+        readColonDelimitedStringToSet(oldSetting, str -> str, targetsFromSetting,
+                /* doMerge = */false);
+        readColonDelimitedStringToSet(newSetting, str -> str, targetsFromSetting,
+                /* doMerge = */true);
+
+        final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
+        userState.mAccessibilityButtonTargets.clear();
+        userState.mAccessibilityButtonTargets.addAll(targetsFromSetting);
+        persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
+                UserHandle.USER_SYSTEM, userState.mAccessibilityButtonTargets, str -> str);
+
+        scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+        onUserStateChangedLocked(userState);
     }
 
     private int getClientStateLocked(AccessibilityUserState userState) {
@@ -1569,8 +1614,8 @@
      */
     private void readComponentNamesFromSettingLocked(String settingName, int userId,
             Set<ComponentName> outComponentNames) {
-        readColonDelimitedSettingToSet(settingName, userId, outComponentNames,
-                str -> ComponentName.unflattenFromString(str));
+        readColonDelimitedSettingToSet(settingName, userId,
+                str -> ComponentName.unflattenFromString(str), outComponentNames);
     }
 
     /**
@@ -1585,8 +1630,8 @@
     private void readComponentNamesFromStringLocked(String names,
             Set<ComponentName> outComponentNames,
             boolean doMerge) {
-        readColonDelimitedStringToSet(names, outComponentNames, doMerge,
-                str -> ComponentName.unflattenFromString(str));
+        readColonDelimitedStringToSet(names, str -> ComponentName.unflattenFromString(str),
+                outComponentNames, doMerge);
     }
 
     @Override
@@ -1596,15 +1641,15 @@
                 componentName -> componentName.flattenToShortString());
     }
 
-    private <T> void readColonDelimitedSettingToSet(String settingName, int userId, Set<T> outSet,
-            Function<String, T> toItem) {
+    private <T> void readColonDelimitedSettingToSet(String settingName, int userId,
+            Function<String, T> toItem, Set<T> outSet) {
         final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                 settingName, userId);
-        readColonDelimitedStringToSet(settingValue, outSet, false, toItem);
+        readColonDelimitedStringToSet(settingValue, toItem, outSet, false);
     }
 
-    private <T> void readColonDelimitedStringToSet(String names, Set<T> outSet, boolean doMerge,
-            Function<String, T> toItem) {
+    private <T> void readColonDelimitedStringToSet(String names, Function<String, T> toItem,
+            Set<T> outSet, boolean doMerge) {
         if (!doMerge) {
             outSet.clear();
         }
@@ -2104,7 +2149,7 @@
         final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userState.mUserId);
         final Set<String> targetsFromSetting = new ArraySet<>();
-        readColonDelimitedStringToSet(settingValue, targetsFromSetting, false, str -> str);
+        readColonDelimitedStringToSet(settingValue, str -> str, targetsFromSetting, false);
         // Fall back to device's default a11y service, only when setting is never updated.
         if (settingValue == null) {
             final String defaultService = mContext.getString(
@@ -2128,7 +2173,7 @@
     private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
         final Set<String> targetsFromSetting = new ArraySet<>();
         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
-                userState.mUserId, targetsFromSetting, str -> str);
+                userState.mUserId, str -> str, targetsFromSetting);
 
         final Set<String> currentTargets =
                 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
@@ -2392,9 +2437,15 @@
      *    (It happens when an enabled accessibility service package is upgraded.)
      *
      * @param packageName The package name to check, or {@code null} to check all services.
+     * @param restoreFromSdkInt The target sdk version of the restored source device, or {@code 0}
+     *                          if the caller is not related to the restore.
      */
     private void migrateAccessibilityButtonSettingsIfNecessaryLocked(
-            AccessibilityUserState userState, @Nullable String packageName) {
+            AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt) {
+        // No need to migrate settings if they are restored from a version after Q.
+        if (restoreFromSdkInt > Build.VERSION_CODES.Q) {
+            return;
+        }
         final Set<String> buttonTargets =
                 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
         int lastSize = buttonTargets.size();
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 44c4bf4..b6f2a47 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -16,8 +16,10 @@
 
 package com.android.server.accessibility.magnification;
 
+import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -61,6 +63,8 @@
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "FullScreenMagnificationController";
 
+    private static final Runnable STUB_RUNNABLE = () -> {
+    };
     public static final float MIN_SCALE = 1.0f;
     public static final float MAX_SCALE = 8.0f;
 
@@ -292,7 +296,7 @@
                     // Adjust the current spec's offsets if necessary.
                     if (updateCurrentSpecWithOffsetsLocked(
                             mCurrentMagnificationSpec.offsetX, mCurrentMagnificationSpec.offsetY)) {
-                        sendSpecToAnimation(mCurrentMagnificationSpec, false);
+                        sendSpecToAnimation(mCurrentMagnificationSpec, null);
                     }
                     onMagnificationChangedLocked();
                 }
@@ -300,17 +304,18 @@
             }
         }
 
-        void sendSpecToAnimation(MagnificationSpec spec, boolean animate) {
+        void sendSpecToAnimation(MagnificationSpec spec, Runnable endCallback) {
             if (DEBUG) {
                 Slog.i(LOG_TAG,
-                        "sendSpecToAnimation(spec = " + spec + ", animate = " + animate + ")");
+                        "sendSpecToAnimation(spec = " + spec + ", endCallback = " + endCallback
+                                + ")");
             }
             if (Thread.currentThread().getId() == mMainThreadId) {
-                mSpecAnimationBridge.updateSentSpecMainThread(spec, animate);
+                mSpecAnimationBridge.updateSentSpecMainThread(spec, endCallback);
             } else {
                 final Message m = PooledLambda.obtainMessage(
                         SpecAnimationBridge::updateSentSpecMainThread,
-                        mSpecAnimationBridge, spec, animate);
+                        mSpecAnimationBridge, spec, endCallback);
                 mControllerCtx.getHandler().sendMessage(m);
             }
         }
@@ -410,6 +415,11 @@
 
         @GuardedBy("mLock")
         boolean reset(boolean animate) {
+            return reset(transformToStubRunnable(animate));
+        }
+
+        @GuardedBy("mLock")
+        boolean reset(Runnable endCallback) {
             if (!mRegistered) {
                 return false;
             }
@@ -420,7 +430,7 @@
                 onMagnificationChangedLocked();
             }
             mIdOfLastServiceToMagnify = INVALID_ID;
-            sendSpecToAnimation(spec, animate);
+            sendSpecToAnimation(spec, endCallback);
             return changed;
         }
 
@@ -448,24 +458,24 @@
             final float centerX = normPivotX + offsetX;
             final float centerY = normPivotY + offsetY;
             mIdOfLastServiceToMagnify = id;
-            return setScaleAndCenter(scale, centerX, centerY, animate, id);
+            return setScaleAndCenter(scale, centerX, centerY, transformToStubRunnable(animate), id);
         }
 
         @GuardedBy("mLock")
         boolean setScaleAndCenter(float scale, float centerX, float centerY,
-                boolean animate, int id) {
+                Runnable endCallback, int id) {
             if (!mRegistered) {
                 return false;
             }
             if (DEBUG) {
                 Slog.i(LOG_TAG,
                         "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX
-                                + ", centerY = " + centerY + ", animate = " + animate
+                                + ", centerY = " + centerY + ", endCallback = " + endCallback
                                 + ", id = " + id
                                 + ")");
             }
             final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
-            sendSpecToAnimation(mCurrentMagnificationSpec, animate);
+            sendSpecToAnimation(mCurrentMagnificationSpec, endCallback);
             if (isMagnifying() && (id != INVALID_ID)) {
                 mIdOfLastServiceToMagnify = id;
             }
@@ -531,7 +541,7 @@
             if (id != INVALID_ID) {
                 mIdOfLastServiceToMagnify = id;
             }
-            sendSpecToAnimation(mCurrentMagnificationSpec, false);
+            sendSpecToAnimation(mCurrentMagnificationSpec, null);
         }
 
         boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) {
@@ -865,12 +875,26 @@
      *         the spec did not change
      */
     public boolean reset(int displayId, boolean animate) {
+        return reset(displayId, animate ?  STUB_RUNNABLE : null);
+    }
+
+    /**
+     * Resets the magnification scale and center, optionally animating the
+     * transition.
+     *
+     * @param displayId The logical display id.
+     * @param endCallback Called when the animation is ended or the spec did not change.
+     *                    {@code null} to transition immediately
+     * @return {@code true} if the magnification spec changed, {@code false} if
+     *         the spec did not change
+     */
+    public boolean reset(int displayId, Runnable endCallback) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
             if (display == null) {
                 return false;
             }
-            return display.reset(animate);
+            return display.reset(endCallback);
         }
     }
 
@@ -921,7 +945,8 @@
             if (display == null) {
                 return false;
             }
-            return display.setScaleAndCenter(Float.NaN, centerX, centerY, animate, id);
+            return display.setScaleAndCenter(Float.NaN, centerX, centerY,
+                    animate ?  STUB_RUNNABLE : null, id);
         }
     }
 
@@ -944,12 +969,35 @@
      */
     public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
             boolean animate, int id) {
+        return setScaleAndCenter(displayId, scale, centerX, centerY,
+                transformToStubRunnable(animate), id);
+    }
+
+    /**
+     * Sets the scale and center of the magnified region, optionally
+     * animating the transition. If animation is disabled, the transition
+     * is immediate.
+     *
+     * @param displayId The logical display id.
+     * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+     * @param centerX the screen-relative X coordinate around which to
+     *                center and scale, or {@link Float#NaN} to leave unchanged
+     * @param centerY the screen-relative Y coordinate around which to
+     *                center and scale, or {@link Float#NaN} to leave unchanged
+     * @param endCallback called when the transition is finished successfully or the spec did not
+     *                   change. {@code null} to transition immediately.
+     * @param id the ID of the service requesting the change
+     * @return {@code true} if the magnification spec changed, {@code false} if
+     *         the spec did not change
+     */
+    public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
+            Runnable endCallback, int id) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
             if (display == null) {
                 return false;
             }
-            return display.setScaleAndCenter(scale, centerX, centerY, animate, id);
+            return display.setScaleAndCenter(scale, centerX, centerY, endCallback, id);
         }
     }
 
@@ -1160,7 +1208,8 @@
      * Class responsible for animating spec on the main thread and sending spec
      * updates to the window manager.
      */
-    private static class SpecAnimationBridge implements ValueAnimator.AnimatorUpdateListener {
+    private static class SpecAnimationBridge implements ValueAnimator.AnimatorUpdateListener,
+            Animator.AnimatorListener {
         private final ControllerContext mControllerCtx;
 
         /**
@@ -1180,6 +1229,8 @@
          */
         private final ValueAnimator mValueAnimator;
 
+        // Called when the callee wants animating and the sent spec matches the target spec.
+        private Runnable mEndCallback;
         private final Object mLock;
 
         private final int mDisplayId;
@@ -1197,6 +1248,7 @@
             mValueAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
             mValueAnimator.setFloatValues(0.0f, 1.0f);
             mValueAnimator.addUpdateListener(this);
+            mValueAnimator.addListener(this);
         }
 
         /**
@@ -1216,24 +1268,36 @@
             }
         }
 
-        public void updateSentSpecMainThread(MagnificationSpec spec, boolean animate) {
+        void updateSentSpecMainThread(MagnificationSpec spec, Runnable endCallback) {
             if (mValueAnimator.isRunning()) {
+                // Avoid AnimationEnd Callback.
+                mEndCallback = null;
                 mValueAnimator.cancel();
             }
 
+            mEndCallback = endCallback;
             // If the current and sent specs don't match, update the sent spec.
             synchronized (mLock) {
                 final boolean changed = !mSentMagnificationSpec.equals(spec);
                 if (changed) {
-                    if (animate) {
+                    if (mEndCallback != null) {
                         animateMagnificationSpecLocked(spec);
                     } else {
                         setMagnificationSpecLocked(spec);
                     }
+                } else {
+                    sendEndCallbackMainThread();
                 }
             }
         }
 
+        private void sendEndCallbackMainThread() {
+            if (mEndCallback != null) {
+                mEndCallback.run();
+                mEndCallback = null;
+            }
+        }
+
         @GuardedBy("mLock")
         private void setMagnificationSpecLocked(MagnificationSpec spec) {
             if (mEnabled) {
@@ -1270,6 +1334,26 @@
                 }
             }
         }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            sendEndCallbackMainThread();
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+
+        }
     }
 
     private static class ScreenStateObserver extends BroadcastReceiver {
@@ -1395,4 +1479,9 @@
             return mAnimationDuration;
         }
     }
+
+    @Nullable
+    private static Runnable transformToStubRunnable(boolean animate) {
+        return animate ? STUB_RUNNABLE : null;
+    }
 }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
index b229e9f..3562205 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -16,11 +16,13 @@
 
 package com.android.server.appwidget;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 
 import com.android.server.AppWidgetBackupBridge;
-import com.android.server.FgThread;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 /**
  * SystemService that publishes an IAppWidgetService.
@@ -49,12 +51,12 @@
     }
 
     @Override
-    public void onStopUser(int userHandle) {
-        mImpl.onUserStopped(userHandle);
+    public void onUserStopping(@NonNull TargetUser user) {
+        mImpl.onUserStopped(user.getUserIdentifier());
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
-        mImpl.reloadWidgetsMaskedStateForGroup(userHandle);
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        mImpl.reloadWidgetsMaskedStateForGroup(to.getUserIdentifier());
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 089861b..663fd62 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -84,6 +84,7 @@
 import com.android.internal.util.SyncResultReceiver;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -363,7 +364,7 @@
     }
 
     @Override // from SystemService
-    public void onSwitchUser(int userHandle) {
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         if (sDebug) Slog.d(TAG, "Hiding UI when user switched");
         mUi.hideAll(null);
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c839ce94..12e6e10 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -19,6 +19,7 @@
 import static java.util.Collections.emptySet;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -60,6 +61,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.backup.utils.RandomAccessFileUtils;
 
 import java.io.File;
@@ -1605,13 +1607,13 @@
         }
 
         @Override
-        public void onUnlockUser(int userId) {
-            sInstance.onUnlockUser(userId);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            sInstance.onUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onStopUser(int userId) {
-            sInstance.onStopUser(userId);
+        public void onUserStopping(@NonNull TargetUser user) {
+            sInstance.onStopUser(user.getUserIdentifier());
         }
 
         @VisibleForTesting
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index a69bd6b..0a11774 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -24,8 +24,6 @@
 import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
 import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 
-import android.app.backup.BackupManager;
-import android.app.backup.BackupManager.OperationType;
 import android.app.backup.IFullBackupRestoreObserver;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -143,7 +141,7 @@
 
     private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
             OutputStream ofstream) throws Exception {
-        // User key will be used to encrypt the master key.
+        // User key will be used to encrypt the encryption key.
         byte[] newUserSalt = mUserBackupManagerService
                 .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
         SecretKey userKey = PasswordUtils
@@ -151,16 +149,16 @@
                         newUserSalt,
                         PasswordUtils.PBKDF2_HASH_ROUNDS);
 
-        // the master key is random for each backup
-        byte[] masterPw = new byte[256 / 8];
-        mUserBackupManagerService.getRng().nextBytes(masterPw);
+        // the encryption key is random for each backup
+        byte[] encryptionKey = new byte[256 / 8];
+        mUserBackupManagerService.getRng().nextBytes(encryptionKey);
         byte[] checksumSalt = mUserBackupManagerService
                 .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
 
-        // primary encryption of the datastream with the random key
+        // primary encryption of the datastream with the encryption key
         Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
-        SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
-        c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
+        SecretKeySpec encryptionKeySpec = new SecretKeySpec(encryptionKey, "AES");
+        c.init(Cipher.ENCRYPT_MODE, encryptionKeySpec);
         OutputStream finalOutput = new CipherOutputStream(ofstream, c);
 
         // line 4: name of encryption algorithm
@@ -169,7 +167,7 @@
         // line 5: user password salt [hex]
         headerbuf.append(PasswordUtils.byteArrayToHex(newUserSalt));
         headerbuf.append('\n');
-        // line 6: master key checksum salt [hex]
+        // line 6: encryption key checksum salt [hex]
         headerbuf.append(PasswordUtils.byteArrayToHex(checksumSalt));
         headerbuf.append('\n');
         // line 7: number of PBKDF2 rounds used [decimal]
@@ -184,21 +182,21 @@
         headerbuf.append(PasswordUtils.byteArrayToHex(IV));
         headerbuf.append('\n');
 
-        // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
+        // line 9: encryption IV + key blob, encrypted by the user key [hex].  Blob format:
         //    [byte] IV length = Niv
         //    [array of Niv bytes] IV itself
-        //    [byte] master key length = Nmk
-        //    [array of Nmk bytes] master key itself
-        //    [byte] MK checksum hash length = Nck
-        //    [array of Nck bytes] master key checksum hash
+        //    [byte] encryption key length = Nek
+        //    [array of Nek bytes] encryption key itself
+        //    [byte] encryption key checksum hash length = Nck
+        //    [array of Nck bytes] encryption key checksum hash
         //
-        // The checksum is the (master key + checksum salt), run through the
+        // The checksum is the (encryption key + checksum salt), run through the
         // stated number of PBKDF2 rounds
         IV = c.getIV();
-        byte[] mk = masterKeySpec.getEncoded();
+        byte[] mk = encryptionKeySpec.getEncoded();
         byte[] checksum = PasswordUtils
                 .makeKeyChecksum(PBKDF_CURRENT,
-                        masterKeySpec.getEncoded(),
+                        encryptionKeySpec.getEncoded(),
                         checksumSalt, PasswordUtils.PBKDF2_HASH_ROUNDS);
 
         ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
@@ -347,15 +345,15 @@
             // When line 4 is not "none", then additional header data follows:
             //
             // line 5: user password salt [hex]
-            // line 6: master key checksum salt [hex]
-            // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
+            // line 6: encryption key checksum salt [hex]
+            // line 7: number of PBKDF2 rounds to use (same for user & encryption key) [decimal]
             // line 8: IV of the user key [hex]
-            // line 9: master key blob [hex]
-            //     IV of the master key, master key itself, master key checksum hash
+            // line 9: encryption key blob [hex]
+            //     IV of the encryption key, encryption key itself, encryption key checksum hash
             //
-            // The master key checksum is the master key plus its checksum salt, run through
+            // The encryption key checksum is the encryption key plus its checksum salt, run through
             // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
-            // correct password for decrypting the archive:  the master key decrypted from
+            // correct password for decrypting the archive:  the encryption key decrypted from
             // the archive using the user-supplied password is also run through PBKDF2 in
             // this way, and if the result does not match the checksum as stored in the
             // archive, then we know that the user-supplied password does not match the
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index 01b40fb..923bb08 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -212,10 +212,9 @@
         return buffer.toString();
     }
 
-    private static InputStream attemptMasterKeyDecryption(String decryptPassword, String algorithm,
-            byte[] userSalt, byte[] ckSalt,
-            int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
-            boolean doLog) {
+    private static InputStream attemptEncryptionKeyDecryption(String decryptPassword,
+            String algorithm, byte[] userSalt, byte[] ckSalt, int rounds, String userIvHex,
+            String encryptionKeyBlobHex, InputStream rawInStream, boolean doLog) {
         InputStream result = null;
 
         try {
@@ -228,31 +227,31 @@
             c.init(Cipher.DECRYPT_MODE,
                     new SecretKeySpec(userKey.getEncoded(), "AES"),
                     ivSpec);
-            byte[] mkCipher = PasswordUtils.hexToByteArray(masterKeyBlobHex);
+            byte[] mkCipher = PasswordUtils.hexToByteArray(encryptionKeyBlobHex);
             byte[] mkBlob = c.doFinal(mkCipher);
 
-            // first, the master key IV
+            // first, the encryption key IV
             int offset = 0;
             int len = mkBlob[offset++];
             IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
             offset += len;
-            // then the master key itself
+            // then the encryption key itself
             len = mkBlob[offset++];
-            byte[] mk = Arrays.copyOfRange(mkBlob,
+            byte[] encryptionKey = Arrays.copyOfRange(mkBlob,
                     offset, offset + len);
             offset += len;
-            // and finally the master key checksum hash
+            // and finally the encryption key checksum hash
             len = mkBlob[offset++];
             byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
                     offset, offset + len);
 
-            // now validate the decrypted master key against the checksum
-            byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, mk, ckSalt,
+            // now validate the decrypted encryption key against the checksum
+            byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, encryptionKey, ckSalt,
                     rounds);
             if (Arrays.equals(calculatedCk, mkChecksum)) {
                 ivSpec = new IvParameterSpec(IV);
                 c.init(Cipher.DECRYPT_MODE,
-                        new SecretKeySpec(mk, "AES"),
+                        new SecretKeySpec(encryptionKey, "AES"),
                         ivSpec);
                 // Only if all of the above worked properly will 'result' be assigned
                 result = new CipherInputStream(rawInStream, c);
@@ -265,7 +264,7 @@
             }
         } catch (BadPaddingException e) {
             // This case frequently occurs when the wrong password is used to decrypt
-            // the master key.  Use the identical "incorrect password" log text as is
+            // the encryption key.  Use the identical "incorrect password" log text as is
             // used in the checksum failure log in order to avoid providing additional
             // information to an attacker.
             if (doLog) {
@@ -273,7 +272,7 @@
             }
         } catch (IllegalBlockSizeException e) {
             if (doLog) {
-                Slog.w(TAG, "Invalid block size in master key");
+                Slog.w(TAG, "Invalid block size in encryption key");
             }
         } catch (NoSuchAlgorithmException e) {
             if (doLog) {
@@ -309,15 +308,15 @@
                 int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
                 String userIvHex = readHeaderLine(rawInStream); // 8
 
-                String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
+                String encryptionKeyBlobHex = readHeaderLine(rawInStream); // 9
 
-                // decrypt the master key blob
-                result = attemptMasterKeyDecryption(decryptPassword, PBKDF_CURRENT,
-                        userSalt, ckSalt, rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
+                // decrypt the encryption key blob
+                result = attemptEncryptionKeyDecryption(decryptPassword, PBKDF_CURRENT, userSalt,
+                        ckSalt, rounds, userIvHex, encryptionKeyBlobHex, rawInStream, false);
                 if (result == null && pbkdf2Fallback) {
-                    result = attemptMasterKeyDecryption(
+                    result = attemptEncryptionKeyDecryption(
                             decryptPassword, PBKDF_FALLBACK, userSalt, ckSalt,
-                            rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
+                            rounds, userIvHex, encryptionKeyBlobHex, rawInStream, true);
                 }
             } else {
                 Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 6d8f9a3..eb38f51 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -28,6 +28,7 @@
 import static java.util.concurrent.TimeUnit.MINUTES;
 
 import android.annotation.CheckResult;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -84,6 +85,7 @@
 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.wm.ActivityTaskManagerInternal;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -189,7 +191,8 @@
     }
 
     @Override
-    public void onUnlockUser(int userHandle) {
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        int userHandle = user.getUserIdentifier();
         Set<Association> associations = readAllAssociations(userHandle);
         if (associations == null || associations.isEmpty()) {
             return;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1093515..e76ec74 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -79,6 +79,7 @@
         ":framework_native_aidl",
         ":gsiservice_aidl",
         ":idmap2_aidl",
+        ":inputconstants_aidl",
         ":installd_aidl",
         ":storaged_aidl",
         ":vold_aidl",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index b241bd1..ad1986a6 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -69,6 +69,7 @@
     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_OVERLAY_CONFIG_SIGNATURE = 16;
 
     @IntDef(flag = true, prefix = "RESOLVE_", value = {
             RESOLVE_NON_BROWSER_ONLY,
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index 7cf5fd6..b7fed87 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -50,5 +50,5 @@
      * Informs battery stats of binder stats for the given work source UID.
      */
     public abstract void noteBinderCallStats(int workSourceUid, long incrementalBinderCallCount,
-            Collection<BinderCallsStats.CallStat> callStats);
+            Collection<BinderCallsStats.CallStat> callStats,  int[] binderThreadNativeTids);
 }
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index f1d74bb..a3c04be 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -59,16 +59,16 @@
 
     /** Resolves the work source of an incoming binder transaction. */
     static class AuthorizedWorkSourceProvider implements BinderInternal.WorkSourceProvider {
-        private ArraySet<Integer> mAppIdWhitelist;
+        private ArraySet<Integer> mAppIdTrustlist;
 
         AuthorizedWorkSourceProvider() {
-            mAppIdWhitelist = new ArraySet<>();
+            mAppIdTrustlist = new ArraySet<>();
         }
 
         public int resolveWorkSourceUid(int untrustedWorkSourceUid) {
             final int callingUid = getCallingUid();
             final int appId = UserHandle.getAppId(callingUid);
-            if (mAppIdWhitelist.contains(appId)) {
+            if (mAppIdTrustlist.contains(appId)) {
                 final int workSource = untrustedWorkSourceUid;
                 final boolean isWorkSourceSet = workSource != Binder.UNSET_WORKSOURCE;
                 return isWorkSourceSet ?  workSource : callingUid;
@@ -77,13 +77,13 @@
         }
 
         public void systemReady(Context context) {
-            mAppIdWhitelist = createAppidWhitelist(context);
+            mAppIdTrustlist = createAppidTrustlist(context);
         }
 
         public void dump(PrintWriter pw, AppIdToPackageMap packageMap) {
             pw.println("AppIds of apps that can set the work source:");
-            final ArraySet<Integer> whitelist = mAppIdWhitelist;
-            for (Integer appId : whitelist) {
+            final ArraySet<Integer> trustlist = mAppIdTrustlist;
+            for (Integer appId : trustlist) {
                 pw.println("\t- " + packageMap.mapAppId(appId));
             }
         }
@@ -92,12 +92,12 @@
             return Binder.getCallingUid();
         }
 
-        private ArraySet<Integer> createAppidWhitelist(Context context) {
-            // Use a local copy instead of mAppIdWhitelist to prevent concurrent read access.
-            final ArraySet<Integer> whitelist = new ArraySet<>();
+        private ArraySet<Integer> createAppidTrustlist(Context context) {
+            // Use a local copy instead of mAppIdTrustlist to prevent concurrent read access.
+            final ArraySet<Integer> trustlist = new ArraySet<>();
 
             // We trust our own process.
-            whitelist.add(UserHandle.getAppId(Process.myUid()));
+            trustlist.add(UserHandle.getAppId(Process.myUid()));
             // We only need to initialize it once. UPDATE_DEVICE_STATS is a system permission.
             final PackageManager pm = context.getPackageManager();
             final String[] permissions = { android.Manifest.permission.UPDATE_DEVICE_STATS };
@@ -110,12 +110,12 @@
                 try {
                     final int uid = pm.getPackageUid(pkgInfo.packageName, queryFlags);
                     final int appId = UserHandle.getAppId(uid);
-                    whitelist.add(appId);
+                    trustlist.add(appId);
                 } catch (NameNotFoundException e) {
                     Slog.e(TAG, "Cannot find uid for package name " + pkgInfo.packageName, e);
                 }
             }
-            return whitelist;
+            return trustlist;
         }
     }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 2e4d44c..f372c6f 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -96,6 +96,8 @@
 
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+    private static final String BLUETOOTH_PRIVILEGED =
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED;
 
     private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
     private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
@@ -306,6 +308,9 @@
             };
 
     public boolean onFactoryReset() {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+                "Need BLUETOOTH_PRIVILEGED permission");
+
         // Wait for stable state if bluetooth is temporary state.
         int state = getState();
         if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 0bcd937..1a1eecd 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -16,10 +16,14 @@
 
 package com.android.server;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.os.UserManager;
 
+import com.android.server.SystemService.TargetUser;
+
 class BluetoothService extends SystemService {
     private BluetoothManagerService mBluetoothManagerService;
     private boolean mInitialized = false;
@@ -52,16 +56,16 @@
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         if (!mInitialized) {
             initialize();
         } else {
-            mBluetoothManagerService.handleOnSwitchUser(userHandle);
+            mBluetoothManagerService.handleOnSwitchUser(to.getUserIdentifier());
         }
     }
 
     @Override
-    public void onUnlockUser(int userHandle) {
-        mBluetoothManagerService.handleOnUnlockUser(userHandle);
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        mBluetoothManagerService.handleOnUnlockUser(user.getUserIdentifier());
     }
 }
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3148a62..a3bcbbe 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.UID_OBSERVER_GONE;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -60,6 +61,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import dalvik.system.DexFile;
@@ -236,16 +238,18 @@
      * individual apps. Make sure that user's preference is pinned into memory.
      */
     @Override
-    public void onSwitchUser(int userHandle) {
-        if (!mUserManager.isManagedProfile(userHandle)) {
-            sendPinAppsMessage(userHandle);
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        int userId = to.getUserIdentifier();
+        if (!mUserManager.isManagedProfile(userId)) {
+            sendPinAppsMessage(userId);
         }
     }
 
     @Override
-    public void onUnlockUser(int userHandle) {
-        if (!mUserManager.isManagedProfile(userHandle)) {
-            sendPinAppsMessage(userHandle);
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        int userId = user.getUserIdentifier();
+        if (!mUserManager.isManagedProfile(userId)) {
+            sendPinAppsMessage(userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1520dd3..eca6036 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -55,6 +55,7 @@
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -152,6 +153,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.pm.Installer;
 import com.android.server.storage.AppFuseBridge;
 import com.android.server.storage.StorageSessionController;
@@ -259,23 +261,23 @@
         }
 
         @Override
-        public void onSwitchUser(int userHandle) {
-            mStorageManagerService.mCurrentUserId = userHandle;
+        public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+            mStorageManagerService.mCurrentUserId = to.getUserIdentifier();
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
-            mStorageManagerService.onUnlockUser(userHandle);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mStorageManagerService.onUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onCleanupUser(int userHandle) {
-            mStorageManagerService.onCleanupUser(userHandle);
+        public void onUserStopped(@NonNull TargetUser user) {
+            mStorageManagerService.onCleanupUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onStopUser(int userHandle) {
-            mStorageManagerService.onStopUser(userHandle);
+        public void onUserStopping(@NonNull TargetUser user) {
+            mStorageManagerService.onStopUser(user.getUserIdentifier());
         }
 
         @Override
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 45d53a1..1496e92 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -23,7 +23,6 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.SystemApi.Client;
-import android.annotation.UserIdInt;
 import android.app.ActivityThread;
 import android.content.Context;
 import android.content.pm.UserInfo;
@@ -263,26 +262,6 @@
     }
 
     /**
-     * @deprecated subclasses should extend {@link #onUserStarting(TargetUser)} instead
-     * (which by default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onStartUser(@UserIdInt int userId) {}
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserStarting(TargetUser)} instead
-     * (which by default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onStartUser(@NonNull UserInfo userInfo) {
-        onStartUser(userInfo.id);
-    }
-
-    /**
      * Called when a new user is starting, for system services to initialize any per-user
      * state they maintain for running users.
      *
@@ -292,27 +271,6 @@
      * @param user target user
      */
     public void onUserStarting(@NonNull TargetUser user) {
-        onStartUser(user.getUserInfo());
-    }
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserUnlocking(TargetUser)} instead (which by
-     * default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onUnlockUser(@UserIdInt int userId) {}
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserUnlocking(TargetUser)} instead (which by
-     * default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onUnlockUser(@NonNull UserInfo userInfo) {
-        onUnlockUser(userInfo.id);
     }
 
     /**
@@ -333,7 +291,6 @@
      * @param user target user
      */
     public void onUserUnlocking(@NonNull TargetUser user) {
-        onUnlockUser(user.getUserInfo());
     }
 
     /**
@@ -348,26 +305,6 @@
     }
 
     /**
-     * @deprecated subclasses should extend {@link #onUserSwitching(TargetUser, TargetUser)} instead
-     * (which by default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onSwitchUser(@UserIdInt int toUserId) {}
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserSwitching(TargetUser, TargetUser)} instead
-     * (which by default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onSwitchUser(@Nullable UserInfo from, @NonNull UserInfo to) {
-        onSwitchUser(to.id);
-    }
-
-    /**
      * Called when switching to a different foreground user, for system services that have
      * special behavior for whichever user is currently in the foreground.  This is called
      * before any application processes are aware of the new user.
@@ -382,28 +319,6 @@
      * @param to the user switching to
      */
     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
-        onSwitchUser((from == null ? null : from.getUserInfo()), to.getUserInfo());
-    }
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserStopping(TargetUser)} instead
-     * (which by default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onStopUser(@UserIdInt int userId) {}
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserStopping(TargetUser)} instead
-     * (which by default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onStopUser(@NonNull UserInfo user) {
-        onStopUser(user.id);
-
     }
 
     /**
@@ -420,27 +335,6 @@
      * @param user target user
      */
     public void onUserStopping(@NonNull TargetUser user) {
-        onStopUser(user.getUserInfo());
-    }
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserStopped(TargetUser)} instead (which by
-     * default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onCleanupUser(@UserIdInt int userId) {}
-
-    /**
-     * @deprecated subclasses should extend {@link #onUserStopped(TargetUser)} instead (which by
-     * default calls this method).
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onCleanupUser(@NonNull UserInfo user) {
-        onCleanupUser(user.id);
     }
 
     /**
@@ -454,7 +348,6 @@
      * @param user target user
      */
     public void onUserStopped(@NonNull TargetUser user) {
-        onCleanupUser(user.getUserInfo());
     }
 
     /**
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7381da1..6d71c8e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -34,7 +34,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.net.LinkProperties;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -46,8 +45,6 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.telephony.Annotation;
-import android.telephony.Annotation.ApnType;
-import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.BarringInfo;
@@ -80,7 +77,9 @@
 import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
+import android.util.ArrayMap;
 import android.util.LocalLog;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
@@ -103,6 +102,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 
 /**
  * Since phone process can be restarted, this class provides a centralized place
@@ -302,13 +302,18 @@
     @RadioPowerState
     private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
 
-    private final LocalLog mLocalLog = new LocalLog(100);
+    private final LocalLog mLocalLog = new LocalLog(200);
 
-    private final LocalLog mListenLog = new LocalLog(100);
+    private final LocalLog mListenLog = new LocalLog(00);
 
-    // Per-phoneMap of APN Type to DataConnectionState
-    private List<Map<Integer, PreciseDataConnectionState>> mPreciseDataConnectionStates =
-            new ArrayList<Map<Integer, PreciseDataConnectionState>>();
+    /**
+     * Per-phone map of precise data connection state. The key of the map is the pair of transport
+     * type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
+     * A precise data connection with state {@link TelephonyManager#DATA_DISCONNECTED} removes
+     * its entry from the map.
+     */
+    private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
+            mPreciseDataConnectionStates;
 
     static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
             PhoneStateListener.LISTEN_REGISTRATION_FAILURE
@@ -521,7 +526,7 @@
             mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
-            mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
+            mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
         }
@@ -610,7 +615,7 @@
             mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
-            mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
+            mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
         }
@@ -1687,38 +1692,25 @@
      *
      * @param phoneId the phoneId carrying the data connection
      * @param subId the subscriptionId for the data connection
-     * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
      * @param preciseState a PreciseDataConnectionState that has info about the data connection
      */
     @Override
-    public void notifyDataConnectionForSubscriber(
-            int phoneId, int subId, @ApnType int apnType, PreciseDataConnectionState preciseState) {
+    public void notifyDataConnectionForSubscriber(int phoneId, int subId,
+            @NonNull PreciseDataConnectionState preciseState) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
 
-        String apn = "";
-        int state = TelephonyManager.DATA_UNKNOWN;
-        int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-        LinkProperties linkProps = null;
+        ApnSetting apnSetting = preciseState.getApnSetting();
 
-        if (preciseState != null) {
-            apn = preciseState.getDataConnectionApn();
-            state = preciseState.getState();
-            networkType = preciseState.getNetworkType();
-            linkProps = preciseState.getLinkProperties();
-        }
-        if (VDBG) {
-            log("notifyDataConnectionForSubscriber: subId=" + subId
-                    + " state=" + state + "' apn='" + apn
-                    + "' apnType=" + apnType + " networkType=" + networkType
-                    + "' preciseState=" + preciseState);
-        }
+        int apnTypes = apnSetting.getApnTypeBitmask();
+        int state = preciseState.getState();
+        int networkType = preciseState.getNetworkType();
 
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 // We only call the callback when the change is for default APN type.
-                if ((ApnSetting.TYPE_DEFAULT & apnType) != 0
+                if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0
                         && (mDataConnectionState[phoneId] != state
                         || mDataConnectionNetworkType[phoneId] != networkType)) {
                     String str = "onDataConnectionStateChanged("
@@ -1747,19 +1739,11 @@
                     mDataConnectionNetworkType[phoneId] = networkType;
                 }
 
-                boolean needsNotify = false;
-                // State has been cleared for this APN Type
-                if (preciseState == null) {
-                    // We try clear the state and check if the state was previously not cleared
-                    needsNotify = mPreciseDataConnectionStates.get(phoneId).remove(apnType) != null;
-                } else {
-                    // We need to check to see if the state actually changed
-                    PreciseDataConnectionState oldPreciseState =
-                            mPreciseDataConnectionStates.get(phoneId).put(apnType, preciseState);
-                    needsNotify = !preciseState.equals(oldPreciseState);
-                }
-
-                if (needsNotify) {
+                Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
+                        preciseState.getApnSetting());
+                PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
+                        .remove(key);
+                if (!Objects.equals(oldState, preciseState)) {
                     for (Record r : mRecords) {
                         if (r.matchPhoneStateListenerEvent(
                                 PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
@@ -1771,54 +1755,22 @@
                             }
                         }
                     }
+                    handleRemoveListLocked();
+
+                    broadcastDataConnectionStateChanged(phoneId, subId, preciseState);
+
+                    String str = "notifyDataConnectionForSubscriber: phoneId=" + phoneId + " subId="
+                            + subId + " " + preciseState;
+                    log(str);
+                    mLocalLog.log(str);
+                }
+
+                // If the state is disconnected, it would be the end of life cycle of a data
+                // connection, so remove it from the cache.
+                if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) {
+                    mPreciseDataConnectionStates.get(phoneId).put(key, preciseState);
                 }
             }
-            handleRemoveListLocked();
-        }
-
-        broadcastDataConnectionStateChanged(state, apn, apnType, subId);
-    }
-
-    /**
-     * Stub to satisfy the ITelephonyRegistry aidl interface; do not use this function.
-     * @see #notifyDataConnectionFailedForSubscriber
-     */
-    public void notifyDataConnectionFailed(String apnType) {
-        loge("This function should not be invoked");
-    }
-
-    private void notifyDataConnectionFailedForSubscriber(int phoneId, int subId, int apnType) {
-        if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
-            return;
-        }
-        if (VDBG) {
-            log("notifyDataConnectionFailedForSubscriber: subId=" + subId
-                    + " apnType=" + apnType);
-        }
-        synchronized (mRecords) {
-            if (validatePhoneId(phoneId)) {
-                mPreciseDataConnectionStates.get(phoneId).put(
-                        apnType,
-                        new PreciseDataConnectionState.Builder()
-                                .setApnSetting(new ApnSetting.Builder()
-                                        .setApnTypeBitmask(apnType)
-                                        .build())
-                                .build());
-                for (Record r : mRecords) {
-                    if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
-                            && idMatch(r.subId, subId, phoneId)) {
-                        try {
-                            r.callback.onPreciseDataConnectionStateChanged(
-                                    mPreciseDataConnectionStates.get(phoneId).get(apnType));
-                        } catch (RemoteException ex) {
-                            mRemoveList.add(r.binder);
-                        }
-                    }
-                }
-            }
-
-            handleRemoveListLocked();
         }
     }
 
@@ -1972,43 +1924,6 @@
     }
 
     @Override
-    public void notifyPreciseDataConnectionFailed(int phoneId, int subId, @ApnType int apnType,
-            String apn, @DataFailureCause int failCause) {
-        if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
-            return;
-        }
-
-        // precise notify invokes imprecise notify
-        notifyDataConnectionFailedForSubscriber(phoneId, subId, apnType);
-
-        synchronized (mRecords) {
-            if (validatePhoneId(phoneId)) {
-                mPreciseDataConnectionStates.get(phoneId).put(
-                        apnType,
-                        new PreciseDataConnectionState.Builder()
-                                .setApnSetting(new ApnSetting.Builder()
-                                        .setApnTypeBitmask(apnType)
-                                        .build())
-                                .setFailCause(failCause)
-                                .build());
-                for (Record r : mRecords) {
-                    if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
-                            && idMatch(r.subId, subId, phoneId)) {
-                        try {
-                            r.callback.onPreciseDataConnectionStateChanged(
-                                    mPreciseDataConnectionStates.get(phoneId).get(apnType));
-                        } catch (RemoteException ex) {
-                            mRemoveList.add(r.binder);
-                        }
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
-    @Override
     public void notifySrvccStateChanged(int subId, @SrvccState int state) {
         if (!checkNotifyPermission("notifySrvccStateChanged()")) {
             return;
@@ -2578,16 +2493,18 @@
         }
     }
 
-    private void broadcastDataConnectionStateChanged(int state, String apn,
-                                                     int apnType, int subId) {
+    private void broadcastDataConnectionStateChanged(int slotIndex, int subId,
+            @NonNull PreciseDataConnectionState pdcs) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
         Intent intent = new Intent(ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
-        intent.putExtra(PHONE_CONSTANTS_STATE_KEY, TelephonyUtils.dataStateToString(state));
-        intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, apn);
+        intent.putExtra(PHONE_CONSTANTS_STATE_KEY,
+                TelephonyUtils.dataStateToString(pdcs.getState()));
+        intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, pdcs.getApnSetting().getApnName());
         intent.putExtra(PHONE_CONSTANTS_DATA_APN_TYPE_KEY,
-                ApnSetting.getApnTypesStringFromBitmask(apnType));
+                ApnSetting.getApnTypesStringFromBitmask(pdcs.getApnSetting().getApnTypeBitmask()));
+        intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, slotIndex);
         intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE);
     }
@@ -2973,7 +2890,7 @@
     /**
      * Returns a string representation of the radio technology (network type)
      * currently in use on the device.
-     * @param subId for which network type is returned
+     * @param type for which network type is returned
      * @return the name of the radio technology
      *
      */
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 915189c..df9dee89 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -16,7 +16,15 @@
 
 package com.android.server;
 
+import static android.app.UiModeManager.DEFAULT_PRIORITY;
+import static android.app.UiModeManager.MODE_NIGHT_AUTO;
+import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
+import static android.app.UiModeManager.MODE_NIGHT_YES;
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.util.TimeUtils.isTimeBetween;
+
 import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -64,6 +72,7 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
@@ -81,13 +90,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import static android.app.UiModeManager.DEFAULT_PRIORITY;
-import static android.app.UiModeManager.MODE_NIGHT_AUTO;
-import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
-import static android.app.UiModeManager.MODE_NIGHT_YES;
-import static android.os.UserHandle.USER_SYSTEM;
-import static android.util.TimeUtils.isTimeBetween;
-
 final class UiModeManagerService extends SystemService {
     private static final String TAG = UiModeManager.class.getSimpleName();
     private static final boolean LOG = false;
@@ -322,8 +324,7 @@
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
-        super.onSwitchUser(userHandle);
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
         verifySetupWizardCompleted();
     }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 72f29b4..2534a53 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -76,6 +76,8 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 
+import libcore.util.NativeAllocationRegistry;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -115,7 +117,6 @@
     // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration.
     private static final long ASYNC_TIMEOUT_MULTIPLIER = 2;
 
-
     // A mapping from the intensity adjustment to the scaling to apply, where the intensity
     // adjustment is defined as the delta between the default intensity level and the user selected
     // intensity level. It's important that we apply the scaling on the delta between the two so
@@ -128,8 +129,6 @@
     private final LinkedList<VibrationInfo> mPreviousVibrations;
     private final int mPreviousVibrationsLimit;
     private final boolean mAllowPriorityVibrationsInLowPowerMode;
-    private final boolean mSupportsAmplitudeControl;
-    private final boolean mSupportsExternalControl;
     private final List<Integer> mSupportedEffects;
     private final long mCapabilities;
     private final int mDefaultVibrationAmplitude;
@@ -174,22 +173,23 @@
     private int mRingIntensity;
     private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
 
-    static native boolean vibratorExists();
-    static native void vibratorInit();
+    static native long vibratorInit();
+
+    static native long vibratorGetFinalizer();
+    static native boolean vibratorExists(long controllerPtr);
     static native void vibratorOn(long milliseconds);
-    static native void vibratorOff();
-    static native boolean vibratorSupportsAmplitudeControl();
-    static native void vibratorSetAmplitude(int amplitude);
-    static native int[] vibratorGetSupportedEffects();
+    static native void vibratorOff(long controllerPtr);
+    static native void vibratorSetAmplitude(long controllerPtr, int amplitude);
+    static native int[] vibratorGetSupportedEffects(long controllerPtr);
     static native long vibratorPerformEffect(long effect, long strength, Vibration vibration,
             boolean withCallback);
     static native void vibratorPerformComposedEffect(
             VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
-    static native boolean vibratorSupportsExternalControl();
-    static native void vibratorSetExternalControl(boolean enabled);
-    static native long vibratorGetCapabilities();
-    static native void vibratorAlwaysOnEnable(long id, long effect, long strength);
-    static native void vibratorAlwaysOnDisable(long id);
+    static native void vibratorSetExternalControl(long controllerPtr, boolean enabled);
+    static native long vibratorGetCapabilities(long controllerPtr);
+    static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect,
+            long strength);
+    static native void vibratorAlwaysOnDisable(long controllerPtr, long id);
 
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
@@ -370,13 +370,20 @@
         mNativeWrapper = injector.getNativeWrapper();
         mH = injector.createHandler(Looper.myLooper());
 
-        mNativeWrapper.vibratorInit();
+        long controllerPtr = mNativeWrapper.vibratorInit();
+        long finalizerPtr = mNativeWrapper.vibratorGetFinalizer();
+
+        if (finalizerPtr != 0) {
+            NativeAllocationRegistry registry =
+                    NativeAllocationRegistry.createMalloced(
+                            VibratorService.class.getClassLoader(), finalizerPtr);
+            registry.registerNativeAllocation(this, controllerPtr);
+        }
+
         // Reset the hardware to a default state, in case this is a runtime
         // restart instead of a fresh boot.
         mNativeWrapper.vibratorOff();
 
-        mSupportsAmplitudeControl = mNativeWrapper.vibratorSupportsAmplitudeControl();
-        mSupportsExternalControl = mNativeWrapper.vibratorSupportsExternalControl();
         mSupportedEffects = asList(mNativeWrapper.vibratorGetSupportedEffects());
         mCapabilities = mNativeWrapper.vibratorGetCapabilities();
 
@@ -605,7 +612,8 @@
         synchronized (mInputDeviceVibrators) {
             // Input device vibrators don't support amplitude controls yet, but are still used over
             // the system vibrator when connected.
-            return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
+            return hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)
+                    && mInputDeviceVibrators.isEmpty();
         }
     }
 
@@ -1288,7 +1296,7 @@
     }
 
     private void doVibratorSetAmplitude(int amplitude) {
-        if (mSupportsAmplitudeControl) {
+        if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
             mNativeWrapper.vibratorSetAmplitude(amplitude);
         }
     }
@@ -1708,14 +1716,25 @@
     @VisibleForTesting
     public static class NativeWrapper {
 
+        private long mNativeControllerPtr = 0;
+
         /** Checks if vibrator exists on device. */
         public boolean vibratorExists() {
-            return VibratorService.vibratorExists();
+            return VibratorService.vibratorExists(mNativeControllerPtr);
         }
 
-        /** Initializes connection to vibrator HAL service. */
-        public void vibratorInit() {
-            VibratorService.vibratorInit();
+        /**
+         * Returns native pointer to newly created controller and initializes connection to vibrator
+         * HAL service.
+         */
+        public long vibratorInit() {
+            mNativeControllerPtr = VibratorService.vibratorInit();
+            return mNativeControllerPtr;
+        }
+
+        /** Returns pointer to native finalizer function to be called by GC. */
+        public long vibratorGetFinalizer() {
+            return VibratorService.vibratorGetFinalizer();
         }
 
         /** Turns vibrator on for given time. */
@@ -1725,22 +1744,17 @@
 
         /** Turns vibrator off. */
         public void vibratorOff() {
-            VibratorService.vibratorOff();
-        }
-
-        /** Returns true if vibrator supports {@link #vibratorSetAmplitude(int)}. */
-        public boolean vibratorSupportsAmplitudeControl() {
-            return VibratorService.vibratorSupportsAmplitudeControl();
+            VibratorService.vibratorOff(mNativeControllerPtr);
         }
 
         /** Sets the amplitude for the vibrator to run. */
         public void vibratorSetAmplitude(int amplitude) {
-            VibratorService.vibratorSetAmplitude(amplitude);
+            VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude);
         }
 
         /** Returns all predefined effects supported by the device vibrator. */
         public int[] vibratorGetSupportedEffects() {
-            return VibratorService.vibratorGetSupportedEffects();
+            return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr);
         }
 
         /** Turns vibrator on to perform one of the supported effects. */
@@ -1755,29 +1769,24 @@
             VibratorService.vibratorPerformComposedEffect(effect, vibration);
         }
 
-        /** Returns true if vibrator supports {@link #vibratorSetExternalControl(boolean)}. */
-        public boolean vibratorSupportsExternalControl() {
-            return VibratorService.vibratorSupportsExternalControl();
-        }
-
         /** Enabled the device vibrator to be controlled by another service. */
         public void vibratorSetExternalControl(boolean enabled) {
-            VibratorService.vibratorSetExternalControl(enabled);
+            VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled);
         }
 
         /** Returns all capabilities of the device vibrator. */
         public long vibratorGetCapabilities() {
-            return VibratorService.vibratorGetCapabilities();
+            return VibratorService.vibratorGetCapabilities(mNativeControllerPtr);
         }
 
         /** Enable always-on vibration with given id and effect. */
         public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
-            VibratorService.vibratorAlwaysOnEnable(id, effect, strength);
+            VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength);
         }
 
         /** Disable always-on vibration for given id. */
         public void vibratorAlwaysOnDisable(long id) {
-            VibratorService.vibratorAlwaysOnDisable(id);
+            VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id);
         }
     }
 
@@ -1852,7 +1861,7 @@
 
         @Override
         public int onExternalVibrationStart(ExternalVibration vib) {
-            if (!mSupportsExternalControl) {
+            if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
                 return SCALE_MUTE;
             }
             if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
@@ -2142,10 +2151,10 @@
                 if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
                     pw.println("  Compose effects");
                 }
-                if (mSupportsAmplitudeControl || hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+                if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
                     pw.println("  Amplitude control");
                 }
-                if (mSupportsExternalControl || hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+                if (hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
                     pw.println("  External control");
                 }
                 if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 7dc0b3a..35e88eb 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -106,6 +106,7 @@
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
@@ -161,14 +162,14 @@
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
-            mService.onUnlockUser(userHandle);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mService.onUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onStopUser(int userHandle) {
-            Slog.i(TAG, "onStopUser " + userHandle);
-            mService.purgeUserData(userHandle);
+        public void onUserStopping(@NonNull TargetUser user) {
+            Slog.i(TAG, "onStopUser " + user);
+            mService.purgeUserData(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1680963..33a92e6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2559,12 +2559,12 @@
 
     private int getAllowMode(Intent service, @Nullable String callingPackage) {
         if (callingPackage == null || service.getComponent() == null) {
-            return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+            return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
         }
         if (callingPackage.equals(service.getComponent().getPackageName())) {
-            return ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
+            return ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
         } else {
-            return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+            return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2f7d105..e546a28 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -41,6 +41,7 @@
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.FactoryTest.FACTORY_TEST_OFF;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -130,10 +131,10 @@
 import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_CMD;
 import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD;
 import static com.android.server.wm.ActivityTaskManagerService.DUMP_STARTER_CMD;
-import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
 
+
 import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.BroadcastBehavior;
@@ -341,6 +342,7 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.SystemServiceManager;
 import com.android.server.ThreadPriorityBooster;
 import com.android.server.UserspaceRebootLogger;
@@ -2333,8 +2335,8 @@
         }
 
         @Override
-        public void onCleanupUser(int userId) {
-            mService.mBatteryStatsService.onCleanupUser(userId);
+        public void onUserStopped(@NonNull TargetUser user) {
+            mService.mBatteryStatsService.onCleanupUser(user.getUserIdentifier());
         }
 
         public ActivityManagerService getService() {
@@ -2443,7 +2445,7 @@
                             ? Collections.emptyList()
                             : Arrays.asList(exemptions.split(","));
                 }
-                if (!ZYGOTE_PROCESS.setApiBlacklistExemptions(mExemptions)) {
+                if (!ZYGOTE_PROCESS.setApiDenylistExemptions(mExemptions)) {
                   Slog.e(TAG, "Failed to set API blacklist exemptions!");
                   // leave mExemptionsStr as is, so we don't try to send the same list again.
                   mExemptions = Collections.emptyList();
@@ -14286,7 +14288,7 @@
     }
 
     private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
-            int callingUid, int[] users, int[] broadcastWhitelist) {
+            int callingUid, int[] users, int[] broadcastAllowList) {
         // TODO: come back and remove this assumption to triage all broadcasts
         int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;
 
@@ -14362,12 +14364,12 @@
         } catch (RemoteException ex) {
             // pm is in same process, this will never happen.
         }
-        if (receivers != null && broadcastWhitelist != null) {
+        if (receivers != null && broadcastAllowList != null) {
             for (int i = receivers.size() - 1; i >= 0; i--) {
                 final int receiverAppId = UserHandle.getAppId(
                         receivers.get(i).activityInfo.applicationInfo.uid);
                 if (receiverAppId >= Process.FIRST_APPLICATION_UID
-                        && Arrays.binarySearch(broadcastWhitelist, receiverAppId) < 0) {
+                        && Arrays.binarySearch(broadcastAllowList, receiverAppId) < 0) {
                     receivers.remove(i);
                 }
             }
@@ -14477,7 +14479,7 @@
             boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
             int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
             @Nullable IBinder backgroundActivityStartsToken,
-            @Nullable int[] broadcastWhitelist) {
+            @Nullable int[] broadcastAllowList) {
         intent = new Intent(intent);
 
         final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14486,10 +14488,10 @@
             intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
         }
 
-        if (userId == UserHandle.USER_ALL && broadcastWhitelist != null) {
-                Slog.e(TAG, "broadcastWhitelist only applies when sending to individual users. "
+        if (userId == UserHandle.USER_ALL && broadcastAllowList != null) {
+                Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. "
                         + "Assuming restrictive whitelist.");
-                broadcastWhitelist = new int[]{};
+                broadcastAllowList = new int[]{};
         }
 
         // By default broadcasts do not go to stopped apps.
@@ -14981,7 +14983,7 @@
         if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                  == 0) {
             receivers = collectReceiverComponents(
-                    intent, resolvedType, callingUid, users, broadcastWhitelist);
+                    intent, resolvedType, callingUid, users, broadcastAllowList);
         }
         if (intent.getComponent() == null) {
             if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
@@ -15011,13 +15013,13 @@
 
         if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
                 + " replacePending=" + replacePending);
-        if (registeredReceivers != null && broadcastWhitelist != null) {
+        if (registeredReceivers != null && broadcastAllowList != null) {
             // if a uid whitelist was provided, remove anything in the application space that wasn't
             // in it.
             for (int i = registeredReceivers.size() - 1; i >= 0; i--) {
                 final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid);
                 if (owningAppId >= Process.FIRST_APPLICATION_UID
-                        && Arrays.binarySearch(broadcastWhitelist, owningAppId) < 0) {
+                        && Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) {
                     registeredReceivers.remove(i);
                 }
             }
@@ -17996,7 +17998,7 @@
         public int broadcastIntent(Intent intent,
                 IIntentReceiver resultTo,
                 String[] requiredPermissions,
-                boolean serialized, int userId, int[] appIdWhitelist) {
+                boolean serialized, int userId, int[] appIdAllowList) {
             synchronized (ActivityManagerService.this) {
                 intent = verifyBroadcastLocked(intent);
 
@@ -18011,7 +18013,7 @@
                             null /*options*/, serialized, false /*sticky*/, callingPid, callingUid,
                             callingUid, callingPid, userId, false /*allowBackgroundStarts*/,
                             null /*tokenNeededForBackgroundActivityStarts*/,
-                            appIdWhitelist);
+                            appIdAllowList);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -18352,19 +18354,20 @@
             throw new SecurityException("Requires permission " + FILTER_EVENTS);
         }
         ProcessRecord proc;
-        long timeout;
+        long timeoutMillis;
         synchronized (this) {
             synchronized (mPidsSelfLocked) {
                 proc = mPidsSelfLocked.get(pid);
             }
-            timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+            timeoutMillis = proc != null ? proc.getInputDispatchingTimeoutMillis() :
+                    DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         }
 
         if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
-            return -1;
+            return 0;
         }
 
-        return timeout;
+        return timeoutMillis;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5081b36..d72998b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -227,8 +227,9 @@
 
         @Override
         public void noteBinderCallStats(int workSourceUid, long incrementatCallCount,
-                Collection<BinderCallsStats.CallStat> callStats) {
-            mStats.noteBinderCallStats(workSourceUid, incrementatCallCount, callStats);
+                Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
+            mStats.noteBinderCallStats(workSourceUid, incrementatCallCount, callStats,
+                    binderThreadNativeTids);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 00b33c4..8970ec4 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -92,7 +92,7 @@
         sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
         sGlobalSettingToTypeMap.put(
-                Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, String.class);
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST, String.class);
         sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
diff --git a/services/core/java/com/android/server/am/PendingTempWhitelists.java b/services/core/java/com/android/server/am/PendingTempWhitelists.java
index b36e3c7..50d58f0 100644
--- a/services/core/java/com/android/server/am/PendingTempWhitelists.java
+++ b/services/core/java/com/android/server/am/PendingTempWhitelists.java
@@ -32,13 +32,13 @@
 
     void put(int uid, ActivityManagerService.PendingTempWhitelist value) {
         mPendingTempWhitelist.put(uid, value);
-        mService.mAtmInternal.onUidAddedToPendingTempWhitelist(uid, value.tag);
+        mService.mAtmInternal.onUidAddedToPendingTempAllowlist(uid, value.tag);
     }
 
     void removeAt(int index) {
         final int uid = mPendingTempWhitelist.keyAt(index);
         mPendingTempWhitelist.removeAt(index);
-        mService.mAtmInternal.onUidRemovedFromPendingTempWhitelist(uid);
+        mService.mAtmInternal.onUidRemovedFromPendingTempAllowlist(uid);
     }
 
     ActivityManagerService.PendingTempWhitelist get(int uid) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index cd4302b..1647fda 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1522,8 +1522,8 @@
         }
     }
 
-    public long getInputDispatchingTimeout() {
-        return mWindowProcessController.getInputDispatchingTimeout();
+    public long getInputDispatchingTimeoutMillis() {
+        return mWindowProcessController.getInputDispatchingTimeoutMillis();
     }
 
     public int getProcessClassEnum() {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 19b671e..0658e81 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -23,11 +23,10 @@
 import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
 import static android.app.ActivityManager.USER_OP_IS_CURRENT;
 import static android.app.ActivityManager.USER_OP_SUCCESS;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
 
@@ -1910,12 +1909,11 @@
                     callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
                 // If the caller does not have either permission, they are always doomed.
                 allow = false;
-            } else if (allowMode == ALLOW_NON_FULL
-                    || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
+            } else if (allowMode == ALLOW_NON_FULL) {
                 // We are blanket allowing non-full access, you lucky caller!
                 allow = true;
-            } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE_OR_FULL
-                        || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL) {
+            } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE
+                        || allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
                 // We may or may not allow this depending on whether the two users are
                 // in the same profile.
                 allow = isSameProfileGroup;
@@ -1942,15 +1940,12 @@
                     builder.append("; this requires ");
                     builder.append(INTERACT_ACROSS_USERS_FULL);
                     if (allowMode != ALLOW_FULL_ONLY) {
-                        if (allowMode == ALLOW_NON_FULL
-                                || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL
-                                || isSameProfileGroup) {
+                        if (allowMode == ALLOW_NON_FULL || isSameProfileGroup) {
                             builder.append(" or ");
                             builder.append(INTERACT_ACROSS_USERS);
                         }
                         if (isSameProfileGroup
-                                && (allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
-                                || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL)) {
+                                && allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
                             builder.append(" or ");
                             builder.append(INTERACT_ACROSS_PROFILES);
                         }
@@ -1977,8 +1972,7 @@
     private boolean canInteractWithAcrossProfilesPermission(
             int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid,
             String callingPackage) {
-        if (allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
-                && allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
+        if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
             return false;
         }
         if (!isSameProfileGroup) {
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index 7e63e72..5db6dc7 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -45,6 +45,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.am.PersistentConnection;
 import com.android.server.appbinding.finders.AppServiceFinder;
 import com.android.server.appbinding.finders.CarrierMessagingClientServiceFinder;
@@ -125,18 +126,18 @@
         }
 
         @Override
-        public void onStartUser(int userHandle) {
-            mService.onStartUser(userHandle);
+        public void onUserStarting(@NonNull TargetUser user) {
+            mService.onStartUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onUnlockUser(int userId) {
-            mService.onUnlockUser(userId);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mService.onUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onStopUser(int userHandle) {
-            mService.onStopUser(userHandle);
+        public void onUserStopping(@NonNull TargetUser user) {
+            mService.onStopUser(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 74f3daf..ee441bf 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,7 +19,6 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
 import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
 import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
@@ -129,7 +128,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.EventLog;
 import android.util.KeyValueListParser;
 import android.util.LongSparseArray;
 import android.util.Pair;
@@ -163,7 +161,6 @@
 import com.android.server.LockGuard;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemServiceManager;
-import com.android.server.am.ActivityManagerService;
 import com.android.server.pm.PackageList;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
@@ -1892,6 +1889,7 @@
         synchronized (this) {
             if (mWriteScheduled) {
                 mWriteScheduled = false;
+                mHandler.removeCallbacks(mWriteRunner);
                 doWrite = true;
             }
         }
@@ -2200,11 +2198,8 @@
                     + " by uid " + Binder.getCallingUid());
         }
 
-        int userId = UserHandle.getUserId(uid);
-
         enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
         verifyIncomingOp(code);
-        verifyIncomingUser(userId);
         code = AppOpsManager.opToSwitch(code);
 
         if (permissionPolicyCallback == null) {
@@ -2449,12 +2444,8 @@
     private void setMode(int code, int uid, @NonNull String packageName, int mode,
             @Nullable IAppOpsCallback permissionPolicyCallback) {
         enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-
-        int userId = UserHandle.getUserId(uid);
-
         verifyIncomingOp(code);
-        verifyIncomingUser(userId);
-        verifyIncomingPackage(packageName, userId);
+        verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
         ArraySet<ModeCallback> repCbs = null;
         code = AppOpsManager.opToSwitch(code);
@@ -2867,11 +2858,8 @@
 
     private int checkOperationImpl(int code, int uid, String packageName,
                 boolean raw) {
-        int userId = UserHandle.getUserId(uid);
-
         verifyIncomingOp(code);
-        verifyIncomingUser(userId);
-        verifyIncomingPackage(packageName, userId);
+        verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
         String resolvedPackageName = resolvePackageName(uid, packageName);
         if (resolvedPackageName == null) {
@@ -2990,15 +2978,10 @@
             String proxiedAttributionTag, int proxyUid, String proxyPackageName,
             String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message,
             boolean shouldCollectMessage) {
-        int proxiedUserId = UserHandle.getUserId(proxiedUid);
-        int proxyUserId = UserHandle.getUserId(proxyUid);
-
         verifyIncomingUid(proxyUid);
         verifyIncomingOp(code);
-        verifyIncomingUser(proxiedUserId);
-        verifyIncomingUser(proxyUserId);
-        verifyIncomingPackage(proxiedPackageName, proxiedUserId);
-        verifyIncomingPackage(proxyPackageName, proxyUserId);
+        verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
+        verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
 
         String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
         if (resolveProxyPackageName == null) {
@@ -3048,12 +3031,9 @@
     private int noteOperationImpl(int code, int uid, @Nullable String packageName,
             @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
             @Nullable String message, boolean shouldCollectMessage) {
-        int userId = UserHandle.getUserId(uid);
-
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        verifyIncomingUser(userId);
-        verifyIncomingPackage(packageName, userId);
+        verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
         String resolvedPackageName = resolvePackageName(uid, packageName);
         if (resolvedPackageName == null) {
@@ -3430,12 +3410,9 @@
     public int startOperation(IBinder clientId, int code, int uid, String packageName,
             String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
             String message, boolean shouldCollectMessage) {
-        int userId = UserHandle.getUserId(uid);
-
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        verifyIncomingUser(userId);
-        verifyIncomingPackage(packageName, userId);
+        verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
         String resolvedPackageName = resolvePackageName(uid, packageName);
         if (resolvedPackageName == null) {
@@ -3515,12 +3492,9 @@
     @Override
     public void finishOperation(IBinder clientId, int code, int uid, String packageName,
             String attributionTag) {
-        int userId = UserHandle.getUserId(uid);
-
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        verifyIncomingUser(userId);
-        verifyIncomingPackage(packageName, userId);
+        verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
         String resolvedPackageName = resolvePackageName(uid, packageName);
         if (resolvedPackageName == null) {
@@ -3749,33 +3723,6 @@
         }
     }
 
-    private void verifyIncomingUser(@UserIdInt int userId) {
-        int callingUid = Binder.getCallingUid();
-        int callingUserId = UserHandle.getUserId(callingUid);
-        int callingPid = Binder.getCallingPid();
-
-        if (callingUserId != userId) {
-            // Prevent endless loop between when checking appops inside of handleIncomingUser
-            if (Binder.getCallingPid() == ActivityManagerService.MY_PID) {
-                return;
-            }
-            long token = Binder.clearCallingIdentity();
-            try {
-                try {
-                    LocalServices.getService(ActivityManagerInternal.class).handleIncomingUser(
-                            callingPid, callingUid, userId, /* allowAll */ false,
-                            ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL, "appop operation", null);
-                } catch (Exception e) {
-                    EventLog.writeEvent(0x534e4554, "153996875", "appop", userId);
-
-                    throw e;
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-    }
-
     private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
         UidState uidState = mUidStates.get(uid);
         if (uidState == null) {
@@ -5855,11 +5802,8 @@
                 return false;
             }
         }
-        int userId = UserHandle.getUserId(uid);
-
         verifyIncomingOp(code);
-        verifyIncomingUser(userId);
-        verifyIncomingPackage(packageName, userId);
+        verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
         final String resolvedPackageName = resolvePackageName(uid, packageName);
         if (resolvedPackageName == null) {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index a3e1b7a..84de25c 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -7,9 +7,6 @@
             "name": "CtsAppOps2TestCases"
         },
         {
-            "name": "CtsAppOpHostTestCases"
-        },
-        {
             "name": "FrameworksServicesTests",
             "options": [
                 {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 45f95fd..2bbbbf1 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -224,12 +224,35 @@
             if (!addSpeakerphoneClient(cb, pid, on)) {
                 return false;
             }
+            if (on) {
+                // Cancel BT SCO ON request by this same client: speakerphone and BT SCO routes
+                // are mutually exclusive.
+                // See symmetrical operation for startBluetoothScoForClient_Sync().
+                mBtHelper.stopBluetoothScoForPid(pid);
+            }
             final boolean wasOn = isSpeakerphoneOn();
             updateSpeakerphoneOn(eventSource);
             return (wasOn != isSpeakerphoneOn());
         }
     }
 
+    /**
+     * Turns speakerphone off for a given pid and update speakerphone state.
+     * @param pid
+     */
+    @GuardedBy("mDeviceStateLock")
+    private void setSpeakerphoneOffForPid(int pid) {
+        SpeakerphoneClient client = getSpeakerphoneClientForPid(pid);
+        if (client == null) {
+            return;
+        }
+        client.unregisterDeathRecipient();
+        mSpeakerphoneClients.remove(client);
+        final String eventSource = new StringBuilder("setSpeakerphoneOffForPid(")
+                .append(pid).append(")").toString();
+        updateSpeakerphoneOn(eventSource);
+    }
+
     @GuardedBy("mDeviceStateLock")
     private void updateSpeakerphoneOn(String eventSource) {
         if (isSpeakerphoneOnRequested()) {
@@ -488,6 +511,10 @@
     /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode,
                 @NonNull String eventSource) {
         synchronized (mDeviceStateLock) {
+            // Cancel speakerphone ON request by this same client: speakerphone and BT SCO routes
+            // are mutually exclusive.
+            // See symmetrical operation for setSpeakerphoneOn(true).
+            setSpeakerphoneOffForPid(Binder.getCallingPid());
             mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
         }
     }
@@ -1379,6 +1406,16 @@
         return false;
     }
 
+    @GuardedBy("mDeviceStateLock")
+    private SpeakerphoneClient getSpeakerphoneClientForPid(int pid) {
+        for (SpeakerphoneClient cl : mSpeakerphoneClients) {
+            if (cl.getPid() == pid) {
+                return cl;
+            }
+        }
+        return null;
+    }
+
     // List of clients requesting speakerPhone ON
     @GuardedBy("mDeviceStateLock")
     private final @NonNull ArrayList<SpeakerphoneClient> mSpeakerphoneClients =
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 2d77d6f..366f303 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -414,13 +414,6 @@
         AppOpsManager.OP_AUDIO_MEDIA_VOLUME             // STREAM_ASSISTANT
     };
 
-    private static Set<Integer> sDeviceVolumeBehaviorSupportedDeviceOutSet = new HashSet<>(
-            Arrays.asList(
-                    AudioSystem.DEVICE_OUT_HDMI,
-                    AudioSystem.DEVICE_OUT_HDMI_ARC,
-                    AudioSystem.DEVICE_OUT_SPDIF,
-                    AudioSystem.DEVICE_OUT_LINE));
-
     private final boolean mUseFixedVolume;
 
     // If absolute volume is supported in AVRCP device
@@ -4952,11 +4945,6 @@
 
     private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut,
             @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
-        if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)) {
-            // unsupported for now
-            throw new IllegalArgumentException("Unsupported device type " + audioSystemDeviceOut);
-        }
-
         // update device masks based on volume behavior
         switch (deviceVolumeBehavior) {
             case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
@@ -4990,20 +4978,14 @@
      * @param device the audio output device type
      * @return the volume behavior for the device
      */
-    public @AudioManager.DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
-            @NonNull AudioDeviceAttributes device) {
+    public @AudioManager.DeviceVolumeBehavior
+    int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
         // verify permissions
         enforceModifyAudioRoutingPermission();
 
         // translate Java device type to native device type (for the devices masks for full / fixed)
         final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
                 device.getType());
-        if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)
-                && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
-                && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_HEARING_AID) {
-            throw new IllegalArgumentException("Unsupported volume behavior "
-                    + audioSystemDeviceOut);
-        }
 
         int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut);
         if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) {
@@ -5855,11 +5837,13 @@
                             caller);
                 }
                 // fire changed intents for all streams
-                mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
-                mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
-                mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
-                        mStreamVolumeAlias[mStreamType]);
-                sendBroadcastToAll(mVolumeChanged);
+                if (index != oldIndex) {
+                    mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
+                    mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
+                    mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
+                            mStreamVolumeAlias[mStreamType]);
+                    sendBroadcastToAll(mVolumeChanged);
+                }
             }
             return changed;
         }
@@ -7497,6 +7481,7 @@
         pw.print("  mIsSingleVolume="); pw.println(mIsSingleVolume);
         pw.print("  mUseFixedVolume="); pw.println(mUseFixedVolume);
         pw.print("  mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
+        pw.print("  mFullVolumeDevices="); pw.println(dumpDeviceTypes(mFullVolumeDevices));
         pw.print("  mExtVolumeController="); pw.println(mExtVolumeController);
         pw.print("  mHdmiCecSink="); pw.println(mHdmiCecSink);
         pw.print("  mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
@@ -9078,7 +9063,7 @@
     }
 
     private void restoreDeviceVolumeBehavior() {
-        for (int deviceType : sDeviceVolumeBehaviorSupportedDeviceOutSet) {
+        for (int deviceType : AudioSystem.DEVICE_OUT_ALL_SET) {
             if (DEBUG_VOL) {
                 Log.d(TAG, "Retrieving Volume Behavior for DeviceType: " + deviceType);
             }
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index b4c41b2..ded0f9a3 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -432,19 +432,35 @@
         // and this must be done on behalf of system server to make sure permissions are granted.
         final long ident = Binder.clearCallingIdentity();
         if (client != null) {
-            AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
-            client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
-                    SCO_MODE_VIRTUAL_CALL);
-            // If a disconnection is pending, the client will be removed whne clearAllScoClients()
-            // is called form receiveBtEvent()
-            if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
-                    && mScoAudioState != SCO_STATE_DEACTIVATING) {
-                client.remove(false /*stop */, true /*unregister*/);
-            }
+            stopAndRemoveClient(client, eventSource);
         }
         Binder.restoreCallingIdentity(ident);
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    /*package*/ synchronized void stopBluetoothScoForPid(int pid) {
+        ScoClient client = getScoClientForPid(pid);
+        if (client == null) {
+            return;
+        }
+        final String eventSource = new StringBuilder("stopBluetoothScoForPid(")
+                .append(pid).append(")").toString();
+        stopAndRemoveClient(client, eventSource);
+    }
+
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    private void stopAndRemoveClient(ScoClient client, @NonNull String eventSource) {
+        AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
+        client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
+                SCO_MODE_VIRTUAL_CALL);
+        // If a disconnection is pending, the client will be removed when clearAllScoClients()
+        // is called form receiveBtEvent()
+        if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
+                && mScoAudioState != SCO_STATE_DEACTIVATING) {
+            client.remove(false /*stop */, true /*unregister*/);
+        }
+    }
 
     /*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
         if (mHearingAid == null) {
@@ -632,21 +648,28 @@
         return result;
     }
 
+    // Return `(null)` if given BluetoothDevice is null. Otherwise, return the anonymized address.
+    private String getAnonymizedAddress(BluetoothDevice btDevice) {
+        return btDevice == null ? "(null)" : btDevice.getAnonymizedAddress();
+    }
+
     // @GuardedBy("AudioDeviceBroker.mSetModeLock")
     //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     @GuardedBy("BtHelper.this")
     private void setBtScoActiveDevice(BluetoothDevice btDevice) {
-        Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
+        Log.i(TAG, "setBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice)
+                + " -> " + getAnonymizedAddress(btDevice));
         final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
         if (Objects.equals(btDevice, previousActiveDevice)) {
             return;
         }
         if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
             Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
-                    + previousActiveDevice);
+                    + getAnonymizedAddress(previousActiveDevice));
         }
         if (!handleBtScoActiveDeviceChange(btDevice, true)) {
-            Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
+            Log.e(TAG, "setBtScoActiveDevice() failed to add new device "
+                    + getAnonymizedAddress(btDevice));
             // set mBluetoothHeadsetDevice to null when failing to add new device
             btDevice = null;
         }
@@ -826,7 +849,8 @@
                                 mBluetoothHeadsetDevice, mScoAudioMode)) {
                             mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
                         } else {
-                            Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice
+                            Log.w(TAG, "requestScoState: connect to "
+                                    + getAnonymizedAddress(mBluetoothHeadsetDevice)
                                     + " failed, mScoAudioMode=" + mScoAudioMode);
                             broadcastScoConnectionState(
                                     AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -974,6 +998,16 @@
         return null;
     }
 
+    @GuardedBy("BtHelper.this")
+    private ScoClient getScoClientForPid(int pid) {
+        for (ScoClient cl : mScoClients) {
+            if (cl.getPid() == pid) {
+                return cl;
+            }
+        }
+        return null;
+    }
+
     // @GuardedBy("AudioDeviceBroker.mSetModeLock")
     //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     @GuardedBy("BtHelper.this")
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 0aeb7ab..4f37dcc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -194,19 +194,19 @@
                     return;
                 }
 
+                if (clientMonitor != mCurrentOperation.clientMonitor) {
+                    Slog.e(getTag(), "[Ignoring Finish] " + clientMonitor + " does not match"
+                            + " current: " + mCurrentOperation.clientMonitor);
+                    return;
+                }
+
+                Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success);
                 mCurrentOperation.state = Operation.STATE_FINISHED;
 
                 if (mCurrentOperation.clientFinishCallback != null) {
                     mCurrentOperation.clientFinishCallback.onClientFinished(clientMonitor, success);
                 }
 
-                if (clientMonitor != mCurrentOperation.clientMonitor) {
-                    throw new IllegalStateException("Mismatched operation, "
-                            + " current: " + mCurrentOperation.clientMonitor
-                            + " received: " + clientMonitor);
-                }
-
-                Slog.d(getTag(), "[Finished] " + clientMonitor + ", success: " + success);
                 if (mGestureAvailabilityDispatcher != null) {
                     mGestureAvailabilityDispatcher.markSensorActive(
                             mCurrentOperation.clientMonitor.getSensorId(), false /* active */);
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 61c99b8..88867fc 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.camera;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -43,6 +45,7 @@
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.util.ArrayList;
@@ -252,20 +255,20 @@
     }
 
     @Override
-    public void onStartUser(int userHandle) {
+    public void onUserStarting(@NonNull TargetUser user) {
         synchronized(mLock) {
             if (mEnabledCameraUsers == null) {
                 // Initialize cameraserver, or update cameraserver if we are recovering
                 // from a crash.
-                switchUserLocked(userHandle);
+                switchUserLocked(user.getUserIdentifier());
             }
         }
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         synchronized(mLock) {
-            switchUserLocked(userHandle);
+            switchUserLocked(to.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index ed3a223..a0bc7d8 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
@@ -59,6 +60,7 @@
 
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
@@ -218,9 +220,9 @@
     }
 
     @Override
-    public void onCleanupUser(int userId) {
+    public void onUserStopped(@NonNull TargetUser user) {
         synchronized (mClipboards) {
-            mClipboards.remove(userId);
+            mClipboards.remove(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index f8774b1..7202f0f 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -171,8 +171,8 @@
             mAllApps.add(UserHandle.getAppId(uid));
 
             final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
-            final boolean hasRestrictedPermission =
-                    hasRestrictedNetworkPermission(app.applicationInfo);
+            final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
+                    || isCarryoverPackage(app.applicationInfo);
 
             if (isNetwork || hasRestrictedPermission) {
                 Boolean permission = mApps.get(uid);
@@ -200,7 +200,7 @@
         for (int i = 0; i < systemPermission.size(); i++) {
             ArraySet<String> perms = systemPermission.valueAt(i);
             int uid = systemPermission.keyAt(i);
-            int netdPermission = 0;
+            int netdPermission = PERMISSION_NONE;
             // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
             if (perms != null) {
                 netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
@@ -225,20 +225,21 @@
     }
 
     @VisibleForTesting
-    boolean hasRestrictedNetworkPermission(@Nullable final ApplicationInfo appInfo) {
-        if (appInfo == null)  return false;
-        // TODO : remove this check in the future(b/162295056). All apps should just
-        // request the appropriate permission for their use case since android Q.
-        if ((appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
+    // TODO : remove this check in the future(b/162295056). All apps should just request the
+    // appropriate permission for their use case since android Q.
+    boolean isCarryoverPackage(@Nullable final ApplicationInfo appInfo) {
+        if (appInfo == null) return false;
+        return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
                 // Backward compatibility for b/114245686, on devices that launched before Q daemons
                 // and apps running as the system UID are exempted from this check.
-                || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q)) {
-            return true;
-        }
+                || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
+    }
 
-        return hasPermission(PERMISSION_MAINLINE_NETWORK_STACK, appInfo.uid)
-                || hasPermission(NETWORK_STACK, appInfo.uid)
-                || hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, appInfo.uid);
+    @VisibleForTesting
+    boolean hasRestrictedNetworkPermission(final int uid) {
+        return hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)
+                || hasPermission(PERMISSION_MAINLINE_NETWORK_STACK, uid)
+                || hasPermission(NETWORK_STACK, uid);
     }
 
     /** Returns whether the given uid has using background network permission. */
@@ -328,8 +329,8 @@
         try {
             final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
             final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
-            final boolean hasRestrictedPermission =
-                    hasRestrictedNetworkPermission(app.applicationInfo);
+            final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
+                    || isCarryoverPackage(app.applicationInfo);
             if (isNetwork || hasRestrictedPermission) {
                 currentPermission = hasRestrictedPermission;
             }
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 9a910bf..1294e90 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -20,6 +20,7 @@
 
 import android.Manifest;
 import android.accounts.Account;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.app.ActivityManager;
@@ -75,6 +76,7 @@
 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.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.FileDescriptor;
@@ -124,26 +126,25 @@
             mService.onBootPhase(phase);
         }
 
-
         @Override
-        public void onStartUser(int userHandle) {
-            mService.onStartUser(userHandle);
+        public void onUserStarting(@NonNull TargetUser user) {
+            mService.onStartUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
-            mService.onUnlockUser(userHandle);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mService.onUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onStopUser(int userHandle) {
-            mService.onStopUser(userHandle);
+        public void onUserStopping(@NonNull TargetUser user) {
+            mService.onStopUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onCleanupUser(int userHandle) {
+        public void onUserStopped(@NonNull TargetUser user) {
             synchronized (mService.mCache) {
-                mService.mCache.remove(userHandle);
+                mService.mCache.remove(user.getUserIdentifier());
             }
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a00c22a..0979ad6 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -104,6 +104,7 @@
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.UiThread;
 import com.android.server.wm.SurfaceAnimationThread;
 import com.android.server.wm.WindowManagerInternal;
@@ -417,7 +418,8 @@
     }
 
     @Override
-    public void onSwitchUser(@UserIdInt int newUserId) {
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        final int newUserId = to.getUserIdentifier();
         final int userSerial = getUserManager().getUserSerialNumber(newUserId);
         synchronized (mSyncRoot) {
             if (mCurrentUserId != newUserId) {
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index fa4ba38..92a3ccf 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -77,6 +77,7 @@
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
@@ -206,30 +207,24 @@
     }
 
     @Override
-    public void onStartUser(int userHandle) {
-        super.onStartUser(userHandle);
-
+    public void onUserStarting(@NonNull TargetUser user) {
         if (mCurrentUser == UserHandle.USER_NULL) {
             final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
-            message.arg1 = userHandle;
+            message.arg1 = user.getUserIdentifier();
             mHandler.sendMessage(message);
         }
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
-        super.onSwitchUser(userHandle);
-
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
-        message.arg1 = userHandle;
+        message.arg1 = to.getUserIdentifier();
         mHandler.sendMessage(message);
     }
 
     @Override
-    public void onStopUser(int userHandle) {
-        super.onStopUser(userHandle);
-
-        if (mCurrentUser == userHandle) {
+    public void onUserStopping(@NonNull TargetUser user) {
+        if (mCurrentUser == user.getUserIdentifier()) {
             final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
             message.arg1 = UserHandle.USER_NULL;
             mHandler.sendMessage(message);
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
index 3c4dae0..c90f297 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
@@ -39,15 +39,19 @@
     @Override
     boolean start() {
         mState = STATE_STARTED;
-        sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
-                source().mService.getPhysicalAddress()));
+        int logicalAddress = getSourceAddress();
+        int physicalAddress = getSourcePath();
+
+        sendCommand(HdmiCecMessageBuilder.buildActiveSource(logicalAddress, physicalAddress));
 
         if (source().getType() == HdmiDeviceInfo.DEVICE_PLAYBACK) {
             // Reports menu-status active to receive <User Control Pressed>.
             sendCommand(
-                    HdmiCecMessageBuilder.buildReportMenuStatus(getSourceAddress(), mDestination,
+                    HdmiCecMessageBuilder.buildReportMenuStatus(logicalAddress, mDestination,
                             Constants.MENU_STATE_ACTIVATED));
         }
+
+        source().setActiveSource(logicalAddress, physicalAddress);
         mState = STATE_FINISHED;
         finish();
         return true;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 7007f8b..0576e91 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -3249,7 +3249,6 @@
             playback.setIsActiveSource(true);
             playback.wakeUpIfActiveSource();
             playback.maySendActiveSource(source);
-            setActiveSource(playback.mAddress, physicalAddress);
         }
 
         if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
@@ -3260,7 +3259,6 @@
                 audioSystem.setIsActiveSource(true);
                 audioSystem.wakeUpIfActiveSource();
                 audioSystem.maySendActiveSource(source);
-                setActiveSource(audioSystem.mAddress, physicalAddress);
             }
         }
     }
@@ -3283,13 +3281,11 @@
             if (audioSystem != null) {
                 audioSystem.setIsActiveSource(false);
             }
-            setActiveSource(playback.mAddress, physicalAddress);
         } else {
             if (audioSystem != null) {
                 audioSystem.setIsActiveSource(true);
                 audioSystem.wakeUpIfActiveSource();
                 audioSystem.maySendActiveSource(sourceAddress);
-                setActiveSource(audioSystem.mAddress, physicalAddress);
             }
         }
     }
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 2672f84..7bbcdaa 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -43,6 +43,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -299,16 +300,16 @@
     }
 
     @Override // from SystemService
-    public void onUnlockUser(int userId) {
+    public void onUserUnlocking(@NonNull TargetUser user) {
         synchronized (mLock) {
-            updateCachedServiceLocked(userId);
+            updateCachedServiceLocked(user.getUserIdentifier());
         }
     }
 
     @Override // from SystemService
-    public void onCleanupUser(int userId) {
+    public void onUserStopped(@NonNull TargetUser user) {
         synchronized (mLock) {
-            removeCachedServiceLocked(userId);
+            removeCachedServiceLocked(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 74ed815..5a423793 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.input;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -66,6 +67,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -181,8 +183,7 @@
 
     // State for vibrator tokens.
     private Object mVibratorLock = new Object();
-    private HashMap<IBinder, VibratorToken> mVibratorTokens =
-            new HashMap<IBinder, VibratorToken>();
+    private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
     private int mNextVibratorTokenValue;
 
     // State for the currently installed input filter.
@@ -190,12 +191,16 @@
     IInputFilter mInputFilter; // guarded by mInputFilterLock
     InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
 
+    private final Object mGestureMonitorPidsLock = new Object();
+    @GuardedBy("mGestureMonitorPidsLock")
+    private final ArrayMap<IBinder, Integer> mGestureMonitorPidsByToken = new ArrayMap<>();
+
     // The associations of input devices to displays by port. Maps from input device port (String)
     // to display id (int). Currently only accessed by InputReader.
     private final Map<String, Integer> mStaticAssociations;
     private final Object mAssociationsLock = new Object();
     @GuardedBy("mAssociationLock")
-    private final Map<String, Integer> mRuntimeAssociations = new HashMap<String, Integer>();
+    private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<String, Integer>();
 
     private static native long nativeInit(InputManagerService service,
             Context context, MessageQueue messageQueue);
@@ -540,13 +545,17 @@
         if (displayId < Display.DEFAULT_DISPLAY) {
             throw new IllegalArgumentException("displayId must >= 0.");
         }
+        final int pid = Binder.getCallingPid();
 
         final long ident = Binder.clearCallingIdentity();
         try {
             InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
             InputMonitorHost host = new InputMonitorHost(inputChannels[0]);
-            nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId,
-                    true /*isGestureMonitor*/);
+            nativeRegisterInputMonitor(
+                    mPtr, inputChannels[0], displayId, true /*isGestureMonitor*/);
+            synchronized (mGestureMonitorPidsLock) {
+                mGestureMonitorPidsByToken.put(inputChannels[1].getToken(), pid);
+            }
             return new InputMonitor(inputChannels[1], host);
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -575,6 +584,9 @@
         if (inputChannel == null) {
             throw new IllegalArgumentException("inputChannel must not be null.");
         }
+        synchronized (mGestureMonitorPidsLock) {
+            mGestureMonitorPidsByToken.remove(inputChannel.getToken());
+        }
 
         nativeUnregisterInputChannel(mPtr, inputChannel);
     }
@@ -1838,6 +1850,7 @@
         if (dumpStr != null) {
             pw.println(dumpStr);
             dumpAssociations(pw);
+            dumpGestureMonitorPidsByToken(pw);
         }
     }
 
@@ -1861,6 +1874,19 @@
         }
     }
 
+    private void dumpGestureMonitorPidsByToken(PrintWriter pw) {
+        synchronized (mGestureMonitorPidsLock) {
+            if (!mGestureMonitorPidsByToken.isEmpty()) {
+                pw.println("Gesture monitor pids by token:");
+                for (int i = 0; i < mGestureMonitorPidsByToken.size(); i++) {
+                    pw.print("  " + i + ": ");
+                    pw.print(" token: " + mGestureMonitorPidsByToken.keyAt(i));
+                    pw.println(" pid: " + mGestureMonitorPidsByToken.valueAt(i));
+                }
+            }
+        }
+    }
+
     private boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
@@ -1883,6 +1909,7 @@
     public void monitor() {
         synchronized (mInputFilterLock) { }
         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
+        synchronized (mGestureMonitorPidsLock) { /* Test if blocked by gesture monitor pids lock */}
         nativeMonitor(mPtr);
     }
 
@@ -1944,6 +1971,9 @@
 
     // Native callback.
     private void notifyInputChannelBroken(IBinder token) {
+        synchronized (mGestureMonitorPidsLock) {
+            mGestureMonitorPidsByToken.remove(token);
+        }
         mWindowManagerCallbacks.notifyInputChannelBroken(token);
     }
 
@@ -1959,8 +1989,12 @@
     // Native callback.
     private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
             String reason) {
-        return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
-                token, reason);
+        Integer gestureMonitorPid;
+        synchronized (mGestureMonitorPidsLock) {
+            gestureMonitorPid = mGestureMonitorPidsByToken.get(token);
+        }
+        return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, token, gestureMonitorPid,
+                reason);
     }
 
     // Native callback.
@@ -2206,22 +2240,48 @@
      * Callback interface implemented by the Window Manager.
      */
     public interface WindowManagerCallbacks {
+        /**
+         * This callback is invoked when the confuguration changes.
+         */
         public void notifyConfigurationChanged();
 
+        /**
+         * This callback is invoked when the lid switch changes state.
+         * @param whenNanos the time when the change occurred
+         * @param lidOpen true if the lid is open
+         */
         public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
 
+        /**
+         * This callback is invoked when the camera lens cover switch changes state.
+         * @param whenNanos the time when the change occurred
+         * @param lensCovered true is the lens is covered
+         */
         public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
 
+        /**
+         * This callback is invoked when an input channel is closed unexpectedly.
+         * @param token the connection token of the broken channel
+         */
         public void notifyInputChannelBroken(IBinder token);
 
         /**
-         * Notifies the window manager about an application that is not responding.
-         * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
+         * Notify the window manager about an application that is not responding.
+         * Return a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
          */
         long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
-                String reason);
+                @Nullable Integer pid, String reason);
 
-        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
+        /**
+         * This callback is invoked when an event first arrives to InputDispatcher and before it is
+         * placed onto InputDispatcher's queue. If this event is intercepted, it will never be
+         * processed by InputDispacher.
+         * @param event The key event that's arriving to InputDispatcher
+         * @param policyFlags The policy flags
+         * @return the flags that tell InputDispatcher how to handle the event (for example, whether
+         * to pass it to the user)
+         */
+        int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
         /**
          * Provides an opportunity for the window manager policy to intercept early motion event
@@ -2231,11 +2291,23 @@
         int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
                 int policyFlags);
 
-        public long interceptKeyBeforeDispatching(IBinder token,
-                KeyEvent event, int policyFlags);
+        /**
+         * This callback is invoked just before the key is about to be sent to an application.
+         * This allows the policy to make some last minute decisions on whether to intercept this
+         * key.
+         * @param token the window token that's about to receive this event
+         * @param event the key event that's being dispatched
+         * @param policyFlags the policy flags
+         * @return negative value if the key should be skipped (not sent to the app). 0 if the key
+         * should proceed getting dispatched to the app. positive value to indicate the additional
+         * time delay, in nanoseconds, to wait before sending this key to the app.
+         */
+        long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
 
-        public KeyEvent dispatchUnhandledKey(IBinder token,
-                KeyEvent event, int policyFlags);
+        /**
+         * Dispatch unhandled key
+         */
+        KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags);
 
         public int getPointerLayer();
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 254285d..3cd70fe 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -159,6 +159,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
 import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
@@ -1596,10 +1597,11 @@
         }
 
         @Override
-        public void onSwitchUser(@UserIdInt int userHandle) {
+        public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
             // Called on ActivityManager thread.
             synchronized (mService.mMethodMap) {
-                mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */);
+                mService.scheduleSwitchUserTaskLocked(to.getUserIdentifier(),
+                        /* clientToBeReset= */ null);
             }
         }
 
@@ -1615,10 +1617,10 @@
         }
 
         @Override
-        public void onUnlockUser(final @UserIdInt int userHandle) {
+        public void onUserUnlocking(@NonNull TargetUser user) {
             // Called on ActivityManager thread.
             mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
-                    userHandle /* arg1 */, 0 /* arg2 */));
+                    /* arg1= */ user.getUserIdentifier(), /* arg2= */ 0));
         }
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 2516e28..937514c 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -94,6 +94,7 @@
 import com.android.internal.view.InputBindResult;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
@@ -249,23 +250,26 @@
 
         @MainThread
         @Override
-        public void onStartUser(@UserIdInt int userId) {
+        public void onUserStarting(@NonNull TargetUser user) {
             mOnWorkerThreadCallback.getHandler().sendMessage(PooledLambda.obtainMessage(
-                    OnWorkerThreadCallback::onStartUser, mOnWorkerThreadCallback, userId));
+                    OnWorkerThreadCallback::onStartUser, mOnWorkerThreadCallback,
+                    user.getUserIdentifier()));
         }
 
         @MainThread
         @Override
-        public void onUnlockUser(@UserIdInt int userId) {
+        public void onUserUnlocking(@NonNull TargetUser user) {
             mOnWorkerThreadCallback.getHandler().sendMessage(PooledLambda.obtainMessage(
-                    OnWorkerThreadCallback::onUnlockUser, mOnWorkerThreadCallback, userId));
+                    OnWorkerThreadCallback::onUnlockUser, mOnWorkerThreadCallback,
+                    user.getUserIdentifier()));
         }
 
         @MainThread
         @Override
-        public void onStopUser(@UserIdInt int userId) {
+        public void onUserStopping(@NonNull TargetUser user) {
             mOnWorkerThreadCallback.getHandler().sendMessage(PooledLambda.obtainMessage(
-                    OnWorkerThreadCallback::onStopUser, mOnWorkerThreadCallback, userId));
+                    OnWorkerThreadCallback::onStopUser, mOnWorkerThreadCallback,
+                    user.getUserIdentifier()));
         }
     }
 
diff --git a/services/core/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
index 1f458ed..6f35c8b 100644
--- a/services/core/java/com/android/server/location/LocationFudger.java
+++ b/services/core/java/com/android/server/location/LocationFudger.java
@@ -112,7 +112,7 @@
     public Location createCoarse(Location fine) {
         synchronized (this) {
             if (fine == mCachedFineLocation) {
-                return new Location(mCachedCoarseLocation);
+                return mCachedCoarseLocation;
             }
         }
 
@@ -154,7 +154,7 @@
             mCachedCoarseLocation = coarse;
         }
 
-        return new Location(mCachedCoarseLocation);
+        return mCachedCoarseLocation;
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index d3558f1..71f1833 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -17,43 +17,27 @@
 package com.android.server.location;
 
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import static android.app.AppOpsManager.OP_MOCK_LOCATION;
-import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
-import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.location.LocationManager.EXTRA_LOCATION_ENABLED;
-import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
-import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
 import static android.location.LocationManager.FUSED_PROVIDER;
 import static android.location.LocationManager.GPS_PROVIDER;
-import static android.location.LocationManager.KEY_LOCATION_CHANGED;
-import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
-import static android.location.LocationManager.MODE_CHANGED_ACTION;
 import static android.location.LocationManager.NETWORK_PROVIDER;
-import static android.location.LocationManager.PASSIVE_PROVIDER;
-import static android.location.LocationManager.PROVIDERS_CHANGED_ACTION;
-import static android.location.LocationManager.invalidateLocalLocationEnabledCaches;
-import static android.os.PowerManager.locationPowerSaveModeToString;
 
 import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
 import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
-import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+import static com.android.server.location.LocationProviderManager.FASTEST_COARSE_INTERVAL_MS;
 
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
 import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
@@ -78,17 +62,9 @@
 import android.location.LocationTime;
 import android.location.util.identity.CallerIdentity;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.IBinder;
 import android.os.ICancellationSignal;
-import android.os.IRemoteCallback;
 import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
-import android.os.PowerManager.ServiceType;
-import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -96,24 +72,16 @@
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
 import android.stats.location.LocationStatsEnums;
-import android.text.TextUtils;
-import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
-import android.util.SparseArray;
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.PendingIntentUtils;
 import com.android.server.SystemService;
-import com.android.server.location.AbstractLocationProvider.State;
 import com.android.server.location.LocationPermissions.PermissionLevel;
 import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
@@ -137,24 +105,17 @@
 import com.android.server.location.util.SystemSettingsHelper;
 import com.android.server.location.util.SystemUserInfoHelper;
 import com.android.server.location.util.UserInfoHelper;
-import com.android.server.location.util.UserInfoHelper.UserListener;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
-import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
-import java.io.PrintStream;
 import java.io.PrintWriter;
 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.Map.Entry;
 import java.util.Objects;
 import java.util.TreeMap;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -241,54 +202,21 @@
     public static final String TAG = "LocationManagerService";
     public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final String WAKELOCK_KEY = "*location*";
-
     private static final String NETWORK_LOCATION_SERVICE_ACTION =
             "com.android.location.service.v3.NetworkLocationProvider";
     private static final String FUSED_LOCATION_SERVICE_ACTION =
             "com.android.location.service.FusedLocationProvider";
 
-    // The maximum interval a location request can have and still be considered "high power".
-    private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
-
-    // The fastest interval that applications can receive coarse locations
-    private static final long FASTEST_COARSE_INTERVAL_MS = 10 * 60 * 1000;
-
-    // maximum age of a location before it is no longer considered "current"
-    private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
-
-    // Location Providers may sometimes deliver location updates
-    // slightly faster that requested - provide grace period so
-    // we don't unnecessarily filter events that are otherwise on
-    // time
-    private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
-
-    private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30000;
-
     private static final String ATTRIBUTION_TAG = "LocationService";
 
     private final Object mLock = new Object();
 
-    private final Handler mHandler;
+    private final Context mContext;
+    private final Injector mInjector;
     private final LocalService mLocalService;
 
-    private final Injector mInjector;
-
-    private final Context mContext;
-    private final AppOpsHelper mAppOpsHelper;
-    private final UserInfoHelper mUserInfoHelper;
-    private final SettingsHelper mSettingsHelper;
-    private final AppForegroundHelper mAppForegroundHelper;
-    private final LocationUsageLogger mLocationUsageLogger;
-
     private final GeofenceManager mGeofenceManager;
-
     @Nullable private volatile GnssManagerService mGnssManagerService = null;
-
-    private final PassiveLocationProviderManager mPassiveManager;
-
-    private PowerManager mPowerManager;
-
     private GeocoderProxy mGeocodeProvider;
 
     @GuardedBy("mLock")
@@ -296,46 +224,30 @@
     @GuardedBy("mLock")
     private boolean mExtraLocationControllerPackageEnabled;
 
-    // @GuardedBy("mLock")
-    // hold lock for write or to prevent write, no lock for read
-    final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
+    // location provider managers
+
+    private final PassiveLocationProviderManager mPassiveManager;
+
+    // @GuardedBy("mProviderManagers")
+    // hold lock for writes, no lock necessary for simple reads
+    private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
             new CopyOnWriteArrayList<>();
 
-    @GuardedBy("mLock")
-    private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
-    private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
-            new HashMap<>();
-
-    private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
-
-    @GuardedBy("mLock")
-    @PowerManager.LocationPowerSaveMode
-    private int mBatterySaverMode;
-
     LocationManagerService(Context context, Injector injector) {
-        mHandler = FgThread.getHandler();
-        mLocalService = new LocalService();
-
-        LocalServices.addService(LocationManagerInternal.class, mLocalService);
-
+        mContext = context.createAttributionContext(ATTRIBUTION_TAG);
         mInjector = injector;
 
-        mContext = context.createAttributionContext(ATTRIBUTION_TAG);
-        mUserInfoHelper = injector.getUserInfoHelper();
-        mAppOpsHelper = injector.getAppOpsHelper();
-        mSettingsHelper = injector.getSettingsHelper();
-        mAppForegroundHelper = injector.getAppForegroundHelper();
-        mLocationUsageLogger = injector.getLocationUsageLogger();
+        mLocalService = new LocalService();
+        LocalServices.addService(LocationManagerInternal.class, mLocalService);
 
         mGeofenceManager = new GeofenceManager(mContext, injector);
 
-        // set up passive provider - we do this early because it has no dependencies on system
-        // services or external code that isn't ready yet, and because this allows the variable to
-        // be final. other more complex providers are initialized later, when system services are
-        // ready
-        mPassiveManager = new PassiveLocationProviderManager();
-        mProviderManagers.add(mPassiveManager);
-        mPassiveManager.setRealProvider(new PassiveProvider(mContext));
+        // set up passive provider first since it will be required for all other location providers,
+        // which are loaded later once the system is ready.
+        mPassiveManager = new PassiveLocationProviderManager(mContext, injector);
+        addLocationProviderManager(mPassiveManager, new PassiveProvider(mContext));
+
+        // TODO: load the gps provider here as well, which will require refactoring
 
         // Let the package manager query which are the default location
         // providers as they get certain permissions granted by default.
@@ -347,253 +259,77 @@
         permissionManagerInternal.setLocationExtraPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationExtraPackageNames));
+    }
 
-        // most startup is deferred until systemReady()
+    @Nullable
+    private LocationProviderManager getLocationProviderManager(String providerName) {
+        if (providerName == null) {
+            return null;
+        }
+
+        for (LocationProviderManager manager : mProviderManagers) {
+            if (providerName.equals(manager.getName())) {
+                return manager;
+            }
+        }
+
+        return null;
+    }
+
+    private LocationProviderManager getOrAddLocationProviderManager(String providerName) {
+        synchronized (mProviderManagers) {
+            for (LocationProviderManager manager : mProviderManagers) {
+                if (providerName.equals(manager.getName())) {
+                    return manager;
+                }
+            }
+
+            LocationProviderManager manager = new LocationProviderManager(mContext, mInjector,
+                    providerName, mPassiveManager);
+            addLocationProviderManager(manager, null);
+            return manager;
+        }
+    }
+
+    private void addLocationProviderManager(LocationProviderManager manager,
+            @Nullable AbstractLocationProvider realProvider) {
+        synchronized (mProviderManagers) {
+            Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);
+
+            manager.startManager();
+            if (realProvider != null) {
+                manager.setRealProvider(realProvider);
+            }
+            mProviderManagers.add(manager);
+        }
+    }
+
+    private void removeLocationProviderManager(LocationProviderManager manager) {
+        synchronized (mProviderManagers) {
+            Preconditions.checkState(getLocationProviderManager(manager.getName()) == manager);
+
+            mProviderManagers.remove(manager);
+            manager.setMockProvider(null);
+            manager.setRealProvider(null);
+            manager.stopManager();
+        }
     }
 
     void onSystemReady() {
-        synchronized (mLock) {
-            mPowerManager = mContext.getSystemService(PowerManager.class);
-
-            // add listeners
-            mContext.getPackageManager().addOnPermissionsChangeListener(
-                    uid -> {
-                        // listener invoked on ui thread, move to our thread to reduce risk of
-                        // blocking ui thread
-                        mHandler.post(() -> {
-                            synchronized (mLock) {
-                                onPermissionsChangedLocked();
-                            }
-                        });
-                    });
-
-            LocalServices.getService(PowerManagerInternal.class).registerLowPowerModeObserver(
-                    ServiceType.LOCATION,
-                    state -> {
-                        // listener invoked on ui thread, move to our thread to reduce risk of
-                        // blocking ui thread
-                        mHandler.post(() -> {
-                            synchronized (mLock) {
-                                onBatterySaverModeChangedLocked(state.locationMode);
-                            }
-                        });
-                    });
-            mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
-
-            mAppOpsHelper.addListener(this::onAppOpChanged);
-
-            mSettingsHelper.addOnLocationEnabledChangedListener(this::onLocationModeChanged);
-            mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
-                    this::onBackgroundThrottleIntervalChanged);
-            mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
-                    this::onBackgroundThrottleWhitelistChanged);
-            mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
-                    this::onIgnoreSettingsWhitelistChanged);
-
-            PackageMonitor packageMonitor = new PackageMonitor() {
-                @Override
-                public void onPackageDisappeared(String packageName, int reason) {
-                    synchronized (mLock) {
-                        LocationManagerService.this.onPackageDisappeared(packageName);
-                    }
-                }
-            };
-            packageMonitor.register(mContext, null, true, mHandler);
-
-            mUserInfoHelper.addListener(this::onUserChanged);
-
-            mAppForegroundHelper.addListener(this::onAppForegroundChanged);
-
-            IntentFilter screenIntentFilter = new IntentFilter();
-            screenIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-            screenIntentFilter.addAction(Intent.ACTION_SCREEN_ON);
-            mContext.registerReceiverAsUser(new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())
-                            || Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
-                        onScreenStateChanged();
-                    }
-                }
-            }, UserHandle.ALL, screenIntentFilter, null, mHandler);
-
-            // initialize the current users. we would get the user started notifications for these
-            // users eventually anyways, but this takes care of it as early as possible.
-            onUserChanged(UserHandle.USER_ALL, UserListener.USER_STARTED);
-        }
+        mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
+                this::onLocationModeChanged);
     }
 
     void onSystemThirdPartyAppsCanStart() {
-        synchronized (mLock) {
-            // prepare providers
-            initializeProvidersLocked();
-        }
-
-        // initialize gnss last because it has no awareness of boot phases and blindly assumes that
-        // all other location providers are loaded at initialization
-        initializeGnss();
-    }
-
-    private void onAppOpChanged(String packageName) {
-        synchronized (mLock) {
-            for (Receiver receiver : mReceivers.values()) {
-                if (receiver.mCallerIdentity.getPackageName().equals(packageName)) {
-                    receiver.updateMonitoring(true);
-                }
-            }
-
-            HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
-            for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
-                String provider = entry.getKey();
-                for (UpdateRecord record : entry.getValue()) {
-                    if (record.mReceiver.mCallerIdentity.getPackageName().equals(packageName)) {
-                        affectedProviders.add(provider);
-                    }
-                }
-            }
-            for (String provider : affectedProviders) {
-                applyRequirementsLocked(provider);
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void onPermissionsChangedLocked() {
-        for (LocationProviderManager manager : mProviderManagers) {
-            applyRequirementsLocked(manager);
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void onBatterySaverModeChangedLocked(int newLocationMode) {
-        if (mBatterySaverMode == newLocationMode) {
-            return;
-        }
-
-        if (D) {
-            Log.d(TAG,
-                    "Battery Saver location mode changed from "
-                            + locationPowerSaveModeToString(mBatterySaverMode) + " to "
-                            + locationPowerSaveModeToString(newLocationMode));
-        }
-
-        mBatterySaverMode = newLocationMode;
-
-        for (LocationProviderManager manager : mProviderManagers) {
-            applyRequirementsLocked(manager);
-        }
-    }
-
-    private void onScreenStateChanged() {
-        synchronized (mLock) {
-            if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
-                for (LocationProviderManager manager : mProviderManagers) {
-                    applyRequirementsLocked(manager);
-                }
-            }
-        }
-    }
-
-    private void onLocationModeChanged(int userId) {
-        boolean enabled = mSettingsHelper.isLocationEnabled(userId);
-        LocationManager.invalidateLocalLocationEnabledCaches();
-
-        if (D) {
-            Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
-        }
-
-        Intent intent = new Intent(MODE_CHANGED_ACTION)
-                .putExtra(EXTRA_LOCATION_ENABLED, enabled)
-                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
-                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
-
-        synchronized (mLock) {
-            for (LocationProviderManager manager : mProviderManagers) {
-                manager.onEnabledChangedLocked(userId);
-            }
-        }
-    }
-
-    private void onPackageDisappeared(String packageName) {
-        synchronized (mLock) {
-            ArrayList<Receiver> deadReceivers = null;
-
-            for (Receiver receiver : mReceivers.values()) {
-                if (receiver.mCallerIdentity.getPackageName().equals(packageName)) {
-                    if (deadReceivers == null) {
-                        deadReceivers = new ArrayList<>();
-                    }
-                    deadReceivers.add(receiver);
-                }
-            }
-
-            // perform removal outside of mReceivers loop
-            if (deadReceivers != null) {
-                for (Receiver receiver : deadReceivers) {
-                    removeUpdatesLocked(receiver);
-                }
-            }
-        }
-    }
-
-    private void onAppForegroundChanged(int uid, boolean foreground) {
-        synchronized (mLock) {
-            HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
-            for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
-                String provider = entry.getKey();
-                for (UpdateRecord record : entry.getValue()) {
-                    if (record.mReceiver.mCallerIdentity.getUid() == uid
-                            && record.mIsForegroundUid != foreground) {
-                        record.updateForeground(foreground);
-
-                        if (!isThrottlingExempt(record.mReceiver.mCallerIdentity)) {
-                            affectedProviders.add(provider);
-                        }
-                    }
-                }
-            }
-            for (String provider : affectedProviders) {
-                applyRequirementsLocked(provider);
-            }
-        }
-    }
-
-    private void onBackgroundThrottleIntervalChanged() {
-        synchronized (mLock) {
-            for (LocationProviderManager manager : mProviderManagers) {
-                applyRequirementsLocked(manager);
-            }
-        }
-    }
-
-    private void onBackgroundThrottleWhitelistChanged() {
-        synchronized (mLock) {
-            for (LocationProviderManager manager : mProviderManagers) {
-                applyRequirementsLocked(manager);
-            }
-        }
-    }
-
-    private void onIgnoreSettingsWhitelistChanged() {
-        synchronized (mLock) {
-            for (LocationProviderManager manager : mProviderManagers) {
-                applyRequirementsLocked(manager);
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void initializeProvidersLocked() {
         LocationProviderProxy networkProvider = LocationProviderProxy.createAndRegister(
                 mContext,
                 NETWORK_LOCATION_SERVICE_ACTION,
                 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
                 com.android.internal.R.string.config_networkLocationProviderPackageName);
         if (networkProvider != null) {
-            LocationProviderManager networkManager = new LocationProviderManager(NETWORK_PROVIDER);
-            mProviderManagers.add(networkManager);
-            networkManager.setRealProvider(networkProvider);
+            LocationProviderManager networkManager = new LocationProviderManager(mContext,
+                    mInjector, NETWORK_PROVIDER, mPassiveManager);
+            addLocationProviderManager(networkManager, networkProvider);
         } else {
             Log.w(TAG, "no network location provider found");
         }
@@ -604,18 +340,28 @@
                 MATCH_DIRECT_BOOT_AWARE | MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).isEmpty(),
                 "Unable to find a direct boot aware fused location provider");
 
-        // bind to fused provider
         LocationProviderProxy fusedProvider = LocationProviderProxy.createAndRegister(
                 mContext,
                 FUSED_LOCATION_SERVICE_ACTION,
                 com.android.internal.R.bool.config_enableFusedLocationOverlay,
                 com.android.internal.R.string.config_fusedLocationProviderPackageName);
         if (fusedProvider != null) {
-            LocationProviderManager fusedManager = new LocationProviderManager(FUSED_PROVIDER);
-            mProviderManagers.add(fusedManager);
-            fusedManager.setRealProvider(fusedProvider);
+            LocationProviderManager fusedManager = new LocationProviderManager(mContext, mInjector,
+                    FUSED_PROVIDER, mPassiveManager);
+            addLocationProviderManager(fusedManager, fusedProvider);
         } else {
-            Log.e(TAG, "no fused location provider found");
+            Log.wtf(TAG, "no fused location provider found");
+        }
+
+        // initialize gnss last because it has no awareness of boot phases and blindly assumes that
+        // all other location providers are loaded at initialization
+        if (GnssManagerService.isGnssSupported()) {
+            mGnssManagerService = new GnssManagerService(mContext, mInjector);
+            mGnssManagerService.onSystemReady();
+
+            LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
+                    GPS_PROVIDER, mPassiveManager);
+            addLocationProviderManager(gnssManager, mGnssManagerService.getGnssLocationProvider());
         }
 
         // bind to geocoder provider
@@ -631,6 +377,18 @@
             Log.e(TAG, "unable to bind ActivityRecognitionProxy");
         }
 
+        // bind to gnss geofence proxy
+        if (GnssManagerService.isGnssSupported()) {
+            IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
+            if (gpsGeofenceHardware != null) {
+                GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
+                if (provider == null) {
+                    Log.e(TAG, "unable to bind to GeofenceProxy");
+                }
+            }
+        }
+
+        // create any predefined test providers
         String[] testProviderStrings = mContext.getResources().getStringArray(
                 com.android.internal.R.array.config_testLocationProviders);
         for (String testProviderString : testProviderStrings) {
@@ -646,763 +404,24 @@
                     Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
                     Integer.parseInt(fragments[8]) /* powerRequirement */,
                     Integer.parseInt(fragments[9]) /* accuracy */);
-            LocationProviderManager manager = getLocationProviderManager(name);
-            if (manager == null) {
-                manager = new LocationProviderManager(name);
-                mProviderManagers.add(manager);
-            }
-            manager.setMockProvider(
+            getOrAddLocationProviderManager(name).setMockProvider(
                     new MockProvider(properties, CallerIdentity.fromContext(mContext)));
         }
     }
 
-    private void initializeGnss() {
-        // Do not hold mLock when calling GnssManagerService#isGnssSupported() which calls into HAL.
-        if (GnssManagerService.isGnssSupported()) {
-            mGnssManagerService = new GnssManagerService(mContext, mInjector);
-            mGnssManagerService.onSystemReady();
+    private void onLocationModeChanged(int userId) {
+        boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
+        LocationManager.invalidateLocalLocationEnabledCaches();
 
-            LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
-            synchronized (mLock) {
-                mProviderManagers.add(gnssManager);
-            }
-            gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
-
-            // bind to geofence proxy
-            IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
-            if (gpsGeofenceHardware != null) {
-                GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
-                if (provider == null) {
-                    Log.e(TAG, "unable to bind to GeofenceProxy");
-                }
-            }
-        }
-    }
-
-    private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
-        switch (change) {
-            case UserListener.CURRENT_USER_CHANGED:
-                synchronized (mLock) {
-                    for (LocationProviderManager manager : mProviderManagers) {
-                        manager.onEnabledChangedLocked(userId);
-                    }
-                }
-                break;
-            case UserListener.USER_STARTED:
-                synchronized (mLock) {
-                    for (LocationProviderManager manager : mProviderManagers) {
-                        manager.onUserStarted(userId);
-                    }
-                }
-                break;
-            case UserListener.USER_STOPPED:
-                synchronized (mLock) {
-                    for (LocationProviderManager manager : mProviderManagers) {
-                        manager.onUserStopped(userId);
-                    }
-                }
-                break;
-        }
-    }
-
-    /**
-     * Location provider manager, manages a LocationProvider.
-     */
-    class LocationProviderManager implements MockableLocationProvider.Listener {
-
-        private final String mName;
-
-        private final LocationFudger mLocationFudger;
-
-        // if the provider is enabled for a given user id - null or not present means unknown
-        @GuardedBy("mLock")
-        private final SparseArray<Boolean> mEnabled;
-
-        // last location for a given user
-        @GuardedBy("mLock")
-        private final SparseArray<Location> mLastLocation;
-
-        // last coarse location for a given user
-        @GuardedBy("mLock")
-        private final SparseArray<Location> mLastCoarseLocation;
-
-        // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
-        protected final MockableLocationProvider mProvider;
-
-        LocationProviderManager(String name) {
-            mName = name;
-            mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
-            mEnabled = new SparseArray<>(2);
-            mLastLocation = new SparseArray<>(2);
-            mLastCoarseLocation = new SparseArray<>(2);
-
-            // initialize last since this lets our reference escape
-            mProvider = new MockableLocationProvider(mLock, this);
+        if (D) {
+            Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
         }
 
-        public String getName() {
-            return mName;
-        }
-
-        public boolean hasProvider() {
-            return mProvider.getProvider() != null;
-        }
-
-        public void setRealProvider(AbstractLocationProvider provider) {
-            mProvider.setRealProvider(provider);
-        }
-
-        public void setMockProvider(@Nullable MockProvider provider) {
-            synchronized (mLock) {
-                mProvider.setMockProvider(provider);
-
-                // when removing a mock provider, also clear any mock last locations and reset the
-                // location fudger. the mock provider could have been used to infer the current
-                // location fudger offsets.
-                if (provider == null) {
-                    for (int i = 0; i < mLastLocation.size(); i++) {
-                        Location lastLocation = mLastLocation.valueAt(i);
-                        if (lastLocation != null && lastLocation.isFromMockProvider()) {
-                            mLastLocation.setValueAt(i, null);
-                        }
-                    }
-
-                    for (int i = 0; i < mLastCoarseLocation.size(); i++) {
-                        Location lastCoarseLocation = mLastCoarseLocation.valueAt(i);
-                        if (lastCoarseLocation != null && lastCoarseLocation.isFromMockProvider()) {
-                            mLastCoarseLocation.setValueAt(i, null);
-                        }
-                    }
-
-                    mLocationFudger.resetOffsets();
-                }
-            }
-        }
-
-        @Nullable
-        public CallerIdentity getProviderIdentity() {
-            return mProvider.getState().identity;
-        }
-
-        @Nullable
-        public ProviderProperties getProperties() {
-            return mProvider.getState().properties;
-        }
-
-        @Nullable
-        public Location getLastLocation(int userId, @PermissionLevel int permissionlevel) {
-            synchronized (mLock) {
-                switch (permissionlevel) {
-                    case PERMISSION_COARSE:
-                        return mLastCoarseLocation.get(userId);
-                    case PERMISSION_FINE:
-                        return mLastLocation.get(userId);
-                    default:
-                        throw new AssertionError();
-                }
-            }
-        }
-
-        public void injectLastLocation(Location location, int userId) {
-            synchronized (mLock) {
-                if (mLastLocation.get(userId) == null) {
-                    setLastLocation(location, userId);
-                }
-            }
-        }
-
-        private void setLastLocation(Location location, int userId) {
-            synchronized (mLock) {
-                mLastLocation.put(userId, location);
-
-                // update last coarse interval only if enough time has passed
-                long timeDeltaMs = Long.MAX_VALUE;
-                Location coarseLocation = mLastCoarseLocation.get(userId);
-                if (coarseLocation != null) {
-                    timeDeltaMs = NANOSECONDS.toMillis(location.getElapsedRealtimeNanos())
-                            - NANOSECONDS.toMillis(coarseLocation.getElapsedRealtimeNanos());
-                }
-                if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
-                    mLastCoarseLocation.put(userId, mLocationFudger.createCoarse(location));
-                }
-            }
-        }
-
-        public void setMockProviderAllowed(boolean enabled) {
-            synchronized (mLock) {
-                if (!mProvider.isMock()) {
-                    throw new IllegalArgumentException(mName + " provider is not a test provider");
-                }
-
-                mProvider.setMockProviderAllowed(enabled);
-            }
-        }
-
-        public void setMockProviderLocation(Location location) {
-            synchronized (mLock) {
-                if (!mProvider.isMock()) {
-                    throw new IllegalArgumentException(mName + " provider is not a test provider");
-                }
-
-                String locationProvider = location.getProvider();
-                if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
-                    // The location has an explicit provider that is different from the mock
-                    // provider name. The caller may be trying to fool us via b/33091107.
-                    EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
-                            mName + "!=" + locationProvider);
-                }
-
-                mProvider.setMockProviderLocation(location);
-            }
-        }
-
-        public List<LocationRequest> getMockProviderRequests() {
-            synchronized (mLock) {
-                if (!mProvider.isMock()) {
-                    throw new IllegalArgumentException(mName + " provider is not a test provider");
-                }
-
-                return mProvider.getCurrentRequest().locationRequests;
-            }
-        }
-
-        public void setRequest(ProviderRequest request) {
-            mProvider.setRequest(request);
-        }
-
-        public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
-            mProvider.sendExtraCommand(uid, pid, command, extras);
-        }
-
-        @GuardedBy("mLock")
-        @Override
-        public void onReportLocation(Location location) {
-            // don't validate mock locations
-            if (!location.isFromMockProvider()) {
-                if (location.getLatitude() == 0 && location.getLongitude() == 0) {
-                    Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
-                    return;
-                }
-            }
-
-            if (!location.isComplete()) {
-                Log.w(TAG, "blocking incomplete location from " + mName + " provider");
-                return;
-            }
-
-            // update last location if the provider is enabled or if servicing a bypass request
-            boolean locationSettingsIgnored = mProvider.getCurrentRequest().locationSettingsIgnored;
-            for (int userId : mUserInfoHelper.getRunningUserIds()) {
-                if (locationSettingsIgnored || isEnabled(userId)) {
-                    setLastLocation(location, userId);
-                }
-            }
-
-            handleLocationChangedLocked(this, location, mLocationFudger.createCoarse(location));
-        }
-
-        @GuardedBy("mLock")
-        @Override
-        public void onReportLocation(List<Location> locations) {
-            if (mGnssManagerService == null || !GPS_PROVIDER.equals(mName)) {
-                return;
-            }
-
-            mGnssManagerService.onReportLocation(locations);
-        }
-
-        @GuardedBy("mLock")
-        @Override
-        public void onStateChanged(State oldState, State newState) {
-            if (oldState.allowed != newState.allowed) {
-                if (D) {
-                    Log.d(TAG, mName + " provider allowed = " + newState.allowed);
-                }
-
-                onEnabledChangedLocked(UserHandle.USER_ALL);
-            }
-        }
-
-        public void onUserStarted(int userId) {
-            if (userId == UserHandle.USER_NULL) {
-                return;
-            } else if (userId == UserHandle.USER_ALL) {
-                for (int runningUserId : mUserInfoHelper.getRunningUserIds()) {
-                    onUserStarted(runningUserId);
-                }
-                return;
-            }
-
-            Preconditions.checkArgument(userId >= 0);
-
-            synchronized (mLock) {
-                // clear the user's prior enabled state to prevent broadcast of enabled state
-                // change. user starts should never result in a broadcast since the state has
-                // technically not changed.
-                mEnabled.put(userId, null);
-                onEnabledChangedLocked(userId);
-            }
-        }
-
-        public void onUserStopped(int userId) {
-            if (userId == UserHandle.USER_NULL) {
-                return;
-            } else if (userId == UserHandle.USER_ALL) {
-                mEnabled.clear();
-                mLastLocation.clear();
-                mLastCoarseLocation.clear();
-                return;
-            }
-
-            Preconditions.checkArgument(userId >= 0);
-
-            synchronized (mLock) {
-                mEnabled.remove(userId);
-                mLastLocation.remove(userId);
-                mLastCoarseLocation.remove(userId);
-            }
-        }
-
-        public boolean isEnabled(int userId) {
-            if (userId == UserHandle.USER_NULL) {
-                // used during initialization - ignore since many lower level operations (checking
-                // settings for instance) do not support the null user
-                return false;
-            }
-
-            Preconditions.checkArgument(userId >= 0);
-
-            synchronized (mLock) {
-                Boolean enabled = mEnabled.get(userId);
-                if (enabled == null) {
-                    // this generally shouldn't occur, but might be possible due to race conditions
-                    // on when we are notified of new users
-                    Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
-                    onEnabledChangedLocked(userId);
-                    enabled = Objects.requireNonNull(mEnabled.get(userId));
-                }
-
-                return enabled;
-            }
-        }
-
-        @GuardedBy("mLock")
-        public void onEnabledChangedLocked(int userId) {
-            if (userId == UserHandle.USER_NULL) {
-                // used during initialization - ignore since many lower level operations (checking
-                // settings for instance) do not support the null user
-                return;
-            } else if (userId == UserHandle.USER_ALL) {
-                for (int runningUserId : mUserInfoHelper.getRunningUserIds()) {
-                    onEnabledChangedLocked(runningUserId);
-                }
-                return;
-            }
-
-            Preconditions.checkArgument(userId >= 0);
-
-            // if any property that contributes to "enabled" here changes state, it MUST result
-            // in a direct or indrect call to onEnabledChangedLocked. this allows the provider to
-            // guarantee that it will always eventually reach the correct state.
-            boolean enabled = mProvider.getState().allowed
-                    && mUserInfoHelper.isCurrentUserId(userId)
-                    && mSettingsHelper.isLocationEnabled(userId);
-
-            Boolean wasEnabled = mEnabled.get(userId);
-            if (wasEnabled != null && wasEnabled == enabled) {
-                return;
-            }
-
-            mEnabled.put(userId, enabled);
-
-            if (D) {
-                Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
-            }
-
-            // clear last locations if we become disabled and if not servicing a bypass request
-            if (!enabled && !mProvider.getCurrentRequest().locationSettingsIgnored) {
-                mLastLocation.put(userId, null);
-                mLastCoarseLocation.put(userId, null);
-            }
-
-            // do not send change notifications if we just saw this user for the first time
-            if (wasEnabled != null) {
-                // fused and passive provider never get public updates for legacy reasons
-                if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
-                    Intent intent = new Intent(PROVIDERS_CHANGED_ACTION)
-                            .putExtra(EXTRA_PROVIDER_NAME, mName)
-                            .putExtra(EXTRA_PROVIDER_ENABLED, enabled)
-                            .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
-                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                    mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
-                }
-            }
-
-            updateProviderEnabledLocked(this, enabled);
-        }
-
-        public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
-            synchronized (mLock) {
-                pw.print(mName + " provider");
-                if (mProvider.isMock()) {
-                    pw.print(" [mock]");
-                }
-                pw.println(":");
-
-                pw.increaseIndent();
-
-                int[] userIds = mUserInfoHelper.getRunningUserIds();
-                for (int userId : userIds) {
-                    if (userIds.length != 1) {
-                        pw.println("user " + userId + ":");
-                        pw.increaseIndent();
-                    }
-                    pw.println("last location=" + mLastLocation.get(userId));
-                    pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
-                    pw.println("enabled=" + isEnabled(userId));
-                    if (userIds.length != 1) {
-                        pw.decreaseIndent();
-                    }
-                }
-            }
-
-            mProvider.dump(fd, pw, args);
-
-            pw.decreaseIndent();
-        }
-    }
-
-    class PassiveLocationProviderManager extends LocationProviderManager {
-
-        private PassiveLocationProviderManager() {
-            super(PASSIVE_PROVIDER);
-        }
-
-        @Override
-        public void setRealProvider(AbstractLocationProvider provider) {
-            Preconditions.checkArgument(provider instanceof PassiveProvider);
-            super.setRealProvider(provider);
-        }
-
-        @Override
-        public void setMockProvider(@Nullable MockProvider provider) {
-            if (provider != null) {
-                throw new IllegalArgumentException("Cannot mock the passive provider");
-            }
-        }
-
-        public void updateLocation(Location location) {
-            synchronized (mLock) {
-                PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
-                Preconditions.checkState(passiveProvider != null);
-
-                long identity = Binder.clearCallingIdentity();
-                try {
-                    passiveProvider.updateLocation(location);
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-        }
-    }
-
-    /**
-     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
-     * location updates.
-     */
-    private final class Receiver extends LocationManagerServiceUtils.LinkedListenerBase implements
-            PendingIntent.OnFinished {
-        private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
-
-        private final ILocationListener mListener;
-        final PendingIntent mPendingIntent;
-        final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
-        private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
-        private final Object mKey;
-
-        final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
-
-        // True if app ops has started monitoring this receiver for locations.
-        private boolean mOpMonitoring;
-        // True if app ops has started monitoring this receiver for high power (gps) locations.
-        private boolean mOpHighPowerMonitoring;
-        private int mPendingBroadcasts;
-        PowerManager.WakeLock mWakeLock;
-
-        private Receiver(ILocationListener listener, PendingIntent intent, CallerIdentity identity,
-                WorkSource workSource, boolean hideFromAppOps) {
-            super(identity);
-            mListener = listener;
-            mPendingIntent = intent;
-            if (listener != null) {
-                mKey = listener.asBinder();
-            } else {
-                mKey = intent;
-            }
-            if (workSource != null && workSource.isEmpty()) {
-                workSource = null;
-            }
-            mWorkSource = workSource;
-            mHideFromAppOps = hideFromAppOps;
-
-            updateMonitoring(true);
-
-            // construct/configure wakelock
-            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
-            if (workSource == null) {
-                workSource = mCallerIdentity.addToWorkSource(null);
-            }
-            mWakeLock.setWorkSource(workSource);
-
-            // For a non-reference counted wakelock, each acquire will reset the timeout, and we
-            // only need to release it once.
-            mWakeLock.setReferenceCounted(false);
-        }
-
-        @Override
-        public boolean equals(Object otherObj) {
-            return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
-        }
-
-        @Override
-        public int hashCode() {
-            return mKey.hashCode();
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder s = new StringBuilder();
-            s.append("Reciever[");
-            s.append(Integer.toHexString(System.identityHashCode(this)));
-            if (mListener != null) {
-                s.append(" listener");
-            } else {
-                s.append(" intent");
-            }
-            for (String p : mUpdateRecords.keySet()) {
-                s.append(" ").append(mUpdateRecords.get(p).toString());
-            }
-            s.append(" monitoring location: ").append(mOpMonitoring);
-            s.append("]");
-            return s.toString();
-        }
-
-        /**
-         * Update AppOp monitoring for this receiver.
-         *
-         * @param allow If true receiver is currently active, if false it's been removed.
-         */
-        public void updateMonitoring(boolean allow) {
-            if (mHideFromAppOps) {
-                return;
-            }
-
-            boolean requestingLocation = false;
-            boolean requestingHighPowerLocation = false;
-            if (allow) {
-                // See if receiver has any enabled update records.  Also note if any update records
-                // are high power (has a high power provider with an interval under a threshold).
-                for (UpdateRecord updateRecord : mUpdateRecords.values()) {
-                    LocationProviderManager manager = getLocationProviderManager(
-                            updateRecord.mProvider);
-                    if (manager == null) {
-                        continue;
-                    }
-                    if (!manager.isEnabled(UserHandle.getUserId(mCallerIdentity.getUid()))
-                            && !isSettingsExempt(updateRecord)) {
-                        continue;
-                    }
-
-                    requestingLocation = true;
-                    ProviderProperties properties = manager.getProperties();
-                    if (properties != null
-                            && properties.mPowerRequirement == Criteria.POWER_HIGH
-                            && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
-                        requestingHighPowerLocation = true;
-                        break;
-                    }
-                }
-            }
-
-            // First update monitoring of any location request (including high power).
-            mOpMonitoring = updateMonitoring(
-                    requestingLocation,
-                    mOpMonitoring,
-                    false);
-
-            // Now update monitoring of high power requests only.
-            mOpHighPowerMonitoring = updateMonitoring(
-                    requestingHighPowerLocation,
-                    mOpHighPowerMonitoring,
-                    true);
-        }
-
-        private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
-                boolean highPower) {
-            if (!currentlyMonitoring) {
-                if (allowMonitoring) {
-                    if (!highPower) {
-                        return mAppOpsHelper.startOpNoThrow(OP_MONITOR_LOCATION, mCallerIdentity);
-                    } else {
-                        return mAppOpsHelper.startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION,
-                                mCallerIdentity);
-                    }
-                }
-            } else {
-                int permissionLevel = LocationPermissions.getPermissionLevel(mContext,
-                        mCallerIdentity.getUid(), mCallerIdentity.getPid());
-                if (!allowMonitoring || permissionLevel == PERMISSION_NONE
-                        || !mAppOpsHelper.checkOpNoThrow(
-                        LocationPermissions.asAppOp(permissionLevel), mCallerIdentity)) {
-                    if (!highPower) {
-                        mAppOpsHelper.finishOp(OP_MONITOR_LOCATION, mCallerIdentity);
-                    } else {
-                        mAppOpsHelper.finishOp(OP_MONITOR_HIGH_POWER_LOCATION, mCallerIdentity);
-                    }
-                    return false;
-                }
-            }
-
-            return currentlyMonitoring;
-        }
-
-        public boolean isListener() {
-            return mListener != null;
-        }
-
-        public boolean isPendingIntent() {
-            return mPendingIntent != null;
-        }
-
-        public ILocationListener getListener() {
-            if (mListener != null) {
-                return mListener;
-            }
-            throw new IllegalStateException("Request for non-existent listener");
-        }
-
-        public boolean callLocationChangedLocked(Location location,
-                LocationRequest locationRequest) {
-            if (mListener != null) {
-                try {
-                    mListener.onLocationChanged(new Location(location), new IRemoteCallback.Stub() {
-                        @Override
-                        public void sendResult(Bundle data) {
-                            synchronized (mLock) {
-                                decrementPendingBroadcastsLocked();
-                            }
-                        }
-                    });
-                    // call this after broadcasting so we do not increment
-                    // if we throw an exception.
-                    incrementPendingBroadcastsLocked();
-                } catch (RemoteException e) {
-                    return false;
-                }
-            } else {
-                Intent locationChanged = new Intent();
-                locationChanged.putExtra(KEY_LOCATION_CHANGED, new Location(location));
-                try {
-                    mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
-                            LocationPermissions.asPermission(
-                                    locationRequest.isCoarse() ? PERMISSION_COARSE
-                                            : PERMISSION_FINE),
-                            PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
-                    // call this after broadcasting so we do not increment
-                    // if we throw an exception.
-                    incrementPendingBroadcastsLocked();
-                } catch (PendingIntent.CanceledException e) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        private boolean callProviderEnabledLocked(String provider, boolean enabled,
-                LocationRequest locationRequest) {
-            // First update AppOp monitoring.
-            // An app may get/lose location access as providers are enabled/disabled.
-            updateMonitoring(true);
-
-            if (mListener != null) {
-                try {
-                    mListener.onProviderEnabledChanged(provider, enabled);
-                } catch (RemoteException e) {
-                    return false;
-                }
-            } else {
-                Intent providerIntent = new Intent();
-                providerIntent.putExtra(KEY_PROVIDER_ENABLED, enabled);
-                try {
-                    mPendingIntent.send(mContext, 0, providerIntent, null, mHandler,
-                            LocationPermissions.asPermission(
-                                    locationRequest.isCoarse() ? PERMISSION_COARSE
-                                            : PERMISSION_FINE),
-                            PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
-                } catch (PendingIntent.CanceledException e) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (mLock) {
-                removeUpdatesLocked(this);
-                clearPendingBroadcastsLocked();
-            }
-        }
-
-        @Override
-        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
-                int resultCode, String resultData, Bundle resultExtras) {
-            synchronized (mLock) {
-                decrementPendingBroadcastsLocked();
-            }
-        }
-
-        // this must be called while synchronized by caller in a synchronized block
-        // containing the sending of the broadcaset
-        private void incrementPendingBroadcastsLocked() {
-            mPendingBroadcasts++;
-            // so wakelock calls will succeed
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        private void decrementPendingBroadcastsLocked() {
-            if (--mPendingBroadcasts == 0) {
-                // so wakelock calls will succeed
-                long identity = Binder.clearCallingIdentity();
-                try {
-                    if (mWakeLock.isHeld()) {
-                        mWakeLock.release();
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-        }
-
-        public void clearPendingBroadcastsLocked() {
-            if (mPendingBroadcasts > 0) {
-                mPendingBroadcasts = 0;
-                // so wakelock calls will succeed
-                long identity = Binder.clearCallingIdentity();
-                try {
-                    if (mWakeLock.isHeld()) {
-                        mWakeLock.release();
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-        }
+        Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
+                .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled)
+                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
     }
 
     @Override
@@ -1459,17 +478,6 @@
         }
     }
 
-    @Nullable
-    LocationProviderManager getLocationProviderManager(String providerName) {
-        for (LocationProviderManager manager : mProviderManagers) {
-            if (providerName.equals(manager.getName())) {
-                return manager;
-            }
-        }
-
-        return null;
-    }
-
     @Override
     public List<String> getAllProviders() {
         ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
@@ -1532,397 +540,16 @@
         return null;
     }
 
-    @GuardedBy("mLock")
-    private void updateProviderEnabledLocked(LocationProviderManager manager, boolean enabled) {
-        ArrayList<Receiver> deadReceivers = null;
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
-        if (records != null) {
-            for (UpdateRecord record : records) {
-                if (!mUserInfoHelper.isCurrentUserId(
-                        UserHandle.getUserId(record.mReceiver.mCallerIdentity.getUid()))) {
-                    continue;
-                }
-
-                // requests that ignore location settings will never provide notifications
-                if (isSettingsExempt(record)) {
-                    continue;
-                }
-
-                // Sends a notification message to the receiver
-                if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), enabled,
-                        record.mRequest)) {
-                    if (deadReceivers == null) {
-                        deadReceivers = new ArrayList<>();
-                    }
-                    deadReceivers.add(record.mReceiver);
-                }
-            }
-        }
-
-        if (deadReceivers != null) {
-            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
-                removeUpdatesLocked(deadReceivers.get(i));
-            }
-        }
-
-        applyRequirementsLocked(manager);
-    }
-
-    @GuardedBy("mLock")
-    private void applyRequirementsLocked(String providerName) {
-        LocationProviderManager manager = getLocationProviderManager(providerName);
-        if (manager != null) {
-            applyRequirementsLocked(manager);
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void applyRequirementsLocked(LocationProviderManager manager) {
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
-        ProviderRequest.Builder providerRequest = new ProviderRequest.Builder();
-
-        // if provider is not active, it should not respond to requests
-
-        if (mProviderManagers.contains(manager) && records != null && !records.isEmpty()) {
-            long backgroundThrottleInterval = mSettingsHelper.getBackgroundThrottleIntervalMs();
-
-            ArrayList<LocationRequest> requests = new ArrayList<>(records.size());
-
-            final boolean isForegroundOnlyMode =
-                    mBatterySaverMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
-            final boolean shouldThrottleRequests =
-                    mBatterySaverMode
-                            == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF
-                            && !mPowerManager.isInteractive();
-            // initialize the low power mode to true and set to false if any of the records requires
-            providerRequest.setLowPowerMode(true);
-            for (UpdateRecord record : records) {
-                CallerIdentity identity = record.mReceiver.mCallerIdentity;
-                if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
-                    continue;
-                }
-
-                if (!mAppOpsHelper.checkOpNoThrow(LocationPermissions.asAppOp(
-                        record.mRequest.isCoarse() ? PERMISSION_COARSE : PERMISSION_FINE),
-                        identity)) {
-                    continue;
-                }
-                final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
-                        || (isForegroundOnlyMode && !record.mIsForegroundUid);
-                if (!manager.isEnabled(identity.getUserId()) || isBatterySaverDisablingLocation) {
-                    if (isSettingsExempt(record)) {
-                        providerRequest.setLocationSettingsIgnored(true);
-                        providerRequest.setLowPowerMode(false);
-                    } else {
-                        continue;
-                    }
-                }
-
-                LocationRequest locationRequest = record.mRealRequest;
-                long interval = locationRequest.getInterval();
-
-
-                // if we're forcing location, don't apply any throttling
-                if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExempt(
-                        record.mReceiver.mCallerIdentity)) {
-                    if (!record.mIsForegroundUid) {
-                        interval = Math.max(interval, backgroundThrottleInterval);
-                    }
-                    if (interval != locationRequest.getInterval()) {
-                        locationRequest = new LocationRequest(locationRequest);
-                        locationRequest.setInterval(interval);
-                    }
-                }
-
-                record.mRequest = locationRequest;
-                requests.add(locationRequest);
-                if (!locationRequest.isLowPowerMode()) {
-                    providerRequest.setLowPowerMode(false);
-                }
-                if (interval < providerRequest.getInterval()) {
-                    providerRequest.setInterval(interval);
-                }
-            }
-
-            providerRequest.setLocationRequests(requests);
-
-            if (providerRequest.getInterval() < Long.MAX_VALUE) {
-                // calculate who to blame for power
-                // This is somewhat arbitrary. We pick a threshold interval
-                // that is slightly higher that the minimum interval, and
-                // spread the blame across all applications with a request
-                // under that threshold.
-                // TODO: overflow
-                long thresholdInterval = (providerRequest.getInterval() + 1000) * 3 / 2;
-                for (UpdateRecord record : records) {
-                    if (mUserInfoHelper.isCurrentUserId(
-                            UserHandle.getUserId(record.mReceiver.mCallerIdentity.getUid()))) {
-                        LocationRequest locationRequest = record.mRequest;
-
-                        // Don't assign battery blame for update records whose
-                        // client has no permission to receive location data.
-                        if (!providerRequest.getLocationRequests().contains(locationRequest)) {
-                            continue;
-                        }
-
-                        if (locationRequest.getInterval() <= thresholdInterval) {
-                            if (record.mReceiver.mWorkSource != null
-                                    && isValidWorkSource(record.mReceiver.mWorkSource)) {
-                                providerRequest.getWorkSource().add(record.mReceiver.mWorkSource);
-                            } else {
-                                // Assign blame to caller if there's no WorkSource associated with
-                                // the request or if it's invalid.
-                                providerRequest.getWorkSource().add(
-                                        record.mReceiver.mCallerIdentity.getUid(),
-                                        record.mReceiver.mCallerIdentity.getPackageName());
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        manager.setRequest(providerRequest.build());
-    }
-
-    /**
-     * Whether a given {@code WorkSource} associated with a Location request is valid.
-     */
-    private static boolean isValidWorkSource(WorkSource workSource) {
-        if (workSource.size() > 0) {
-            // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
-            // by tags.
-            return workSource.getPackageName(0) != null;
-        } else {
-            // For now, make sure callers have supplied an attribution tag for use with
-            // AppOpsManager. This might be relaxed in the future.
-            final List<WorkChain> workChains = workSource.getWorkChains();
-            return workChains != null && !workChains.isEmpty()
-                    && workChains.get(0).getAttributionTag() != null;
-        }
-    }
-
     @Override
     public String[] getBackgroundThrottlingWhitelist() {
-        return mSettingsHelper.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
+        return mInjector.getSettingsHelper().getBackgroundThrottlePackageWhitelist().toArray(
+                new String[0]);
     }
 
     @Override
     public String[] getIgnoreSettingsWhitelist() {
-        return mSettingsHelper.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
-    }
-
-    private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
-        if (callerIdentity.getUid() == Process.SYSTEM_UID) {
-            return true;
-        }
-
-        if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
-                callerIdentity.getPackageName())) {
-            return true;
-        }
-
-        return mLocalService.isProvider(null, callerIdentity);
-
-    }
-
-    private boolean isSettingsExempt(UpdateRecord record) {
-        if (!record.mRealRequest.isLocationSettingsIgnored()) {
-            return false;
-        }
-
-        if (mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
-                record.mReceiver.mCallerIdentity.getPackageName())) {
-            return true;
-        }
-
-        return mLocalService.isProvider(null, record.mReceiver.mCallerIdentity);
-    }
-
-    private class UpdateRecord {
-        final String mProvider;
-        private final LocationRequest mRealRequest;  // original request from client
-        LocationRequest mRequest;  // possibly throttled version of the request
-        private final Receiver mReceiver;
-        private boolean mIsForegroundUid;
-        private Location mLastFixBroadcast;
-        private Throwable mStackTrace;  // for debugging only
-        private long mExpirationRealtimeMs;
-
-        /**
-         * Note: must be constructed with lock held.
-         */
-        private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
-            if (Build.IS_DEBUGGABLE) {
-                Preconditions.checkState(Thread.holdsLock(mLock));
-            }
-            mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
-            mProvider = provider;
-            mRealRequest = request;
-            mRequest = request;
-            mReceiver = receiver;
-            mIsForegroundUid = mAppForegroundHelper.isAppForeground(
-                    mReceiver.mCallerIdentity.getUid());
-
-            if (D && receiver.mCallerIdentity.getPid() == Process.myPid()) {
-                mStackTrace = new Throwable();
-            }
-
-            ArrayList<UpdateRecord> records = mRecordsByProvider.computeIfAbsent(provider,
-                    k -> new ArrayList<>());
-            if (!records.contains(this)) {
-                records.add(this);
-            }
-
-            // Update statistics for historical location requests by package/provider
-            mRequestStatistics.startRequesting(
-                    mReceiver.mCallerIdentity.getPackageName(),
-                    mReceiver.mCallerIdentity.getAttributionTag(),
-                    provider, request.getInterval(), mIsForegroundUid);
-        }
-
-        /**
-         * Method to be called when record changes foreground/background
-         */
-        private void updateForeground(boolean isForeground) {
-            mIsForegroundUid = isForeground;
-            mRequestStatistics.updateForeground(
-                    mReceiver.mCallerIdentity.getPackageName(),
-                    mReceiver.mCallerIdentity.getAttributionTag(),
-                    mProvider, isForeground);
-        }
-
-        /**
-         * Method to be called when a record will no longer be used.
-         */
-        private void disposeLocked(boolean removeReceiver) {
-            if (Build.IS_DEBUGGABLE) {
-                Preconditions.checkState(Thread.holdsLock(mLock));
-            }
-
-            CallerIdentity identity = mReceiver.mCallerIdentity;
-            mRequestStatistics.stopRequesting(identity.getPackageName(),
-                    identity.getAttributionTag(),
-                    mProvider);
-
-            mLocationUsageLogger.logLocationApiUsage(
-                    LocationStatsEnums.USAGE_ENDED,
-                    LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
-                    identity.getPackageName(),
-                    mRealRequest,
-                    mReceiver.isListener(),
-                    mReceiver.isPendingIntent(),
-                    /* geofence= */ null,
-                    mAppForegroundHelper.isAppForeground(mReceiver.mCallerIdentity.getUid()));
-
-            // remove from mRecordsByProvider
-            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
-            if (globalRecords != null) {
-                globalRecords.remove(this);
-            }
-
-            if (!removeReceiver) return;  // the caller will handle the rest
-
-            // remove from Receiver#mUpdateRecords
-            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
-            receiverRecords.remove(this.mProvider);
-
-            // and also remove the Receiver if it has no more update records
-            if (receiverRecords.size() == 0) {
-                removeUpdatesLocked(mReceiver);
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder b = new StringBuilder("UpdateRecord[");
-            b.append(mProvider).append(" ");
-            b.append(mReceiver.mCallerIdentity).append(" ");
-            if (!mIsForegroundUid) {
-                b.append("(background) ");
-            }
-            b.append(mRealRequest).append(" ").append(mReceiver.mWorkSource);
-
-            if (mStackTrace != null) {
-                ByteArrayOutputStream tmp = new ByteArrayOutputStream();
-                mStackTrace.printStackTrace(new PrintStream(tmp));
-                b.append("\n\n").append(tmp.toString()).append("\n");
-            }
-
-            b.append("]");
-            return b.toString();
-        }
-    }
-
-    @GuardedBy("mLock")
-    private Receiver getReceiverLocked(ILocationListener listener, CallerIdentity identity,
-            WorkSource workSource, boolean hideFromAppOps) {
-        IBinder binder = listener.asBinder();
-        Receiver receiver = mReceivers.get(binder);
-        if (receiver == null && identity != null) {
-            receiver = new Receiver(listener, null, identity, workSource,
-                    hideFromAppOps);
-            if (!receiver.linkToListenerDeathNotificationLocked(
-                    receiver.getListener().asBinder())) {
-                return null;
-            }
-            mReceivers.put(binder, receiver);
-        }
-        return receiver;
-    }
-
-    @GuardedBy("mLock")
-    private Receiver getReceiverLocked(PendingIntent intent, CallerIdentity identity,
-            WorkSource workSource, boolean hideFromAppOps) {
-        Receiver receiver = mReceivers.get(intent);
-        if (receiver == null && identity != null) {
-            receiver = new Receiver(null, intent, identity, workSource,
-                    hideFromAppOps);
-            mReceivers.put(intent, receiver);
-        }
-        return receiver;
-    }
-
-    /**
-     * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
-     * and consistency requirements.
-     *
-     * @param request the LocationRequest from which to create a sanitized version
-     * @return a version of request that meets the given resolution and consistency requirements
-     * @hide
-     */
-    private LocationRequest createSanitizedRequest(LocationRequest request,
-            boolean callerHasLocationHardwarePermission, int permissionLevel) {
-        LocationRequest sanitizedRequest = new LocationRequest(request);
-        if (!callerHasLocationHardwarePermission) {
-            // allow setting low power mode only for callers with location hardware permission
-            sanitizedRequest.setLowPowerMode(false);
-        }
-        if (permissionLevel < PERMISSION_FINE) {
-            sanitizedRequest.setCoarse(true);
-            switch (sanitizedRequest.getQuality()) {
-                case LocationRequest.ACCURACY_FINE:
-                    sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
-                    break;
-                case LocationRequest.POWER_HIGH:
-                    sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
-                    break;
-            }
-            // throttle
-            if (sanitizedRequest.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
-                sanitizedRequest.setInterval(FASTEST_COARSE_INTERVAL_MS);
-            }
-            if (sanitizedRequest.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
-                sanitizedRequest.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
-            }
-        } else {
-            sanitizedRequest.setCoarse(false);
-        }
-        // make getFastestInterval() the minimum of interval and fastest interval
-        if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
-            sanitizedRequest.setFastestInterval(request.getInterval());
-        }
-        return sanitizedRequest;
+        return mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist().toArray(
+                new String[0]);
     }
 
     @Override
@@ -1930,45 +557,24 @@
             String packageName, String attributionTag, String listenerId) {
         CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
                 listenerId);
-        int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
-        LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+        int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+                identity.getPid());
+        LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
                 PERMISSION_COARSE);
 
-        WorkSource workSource = request.getWorkSource();
-        if (workSource != null && !workSource.isEmpty()) {
-            mContext.enforceCallingOrSelfPermission(
-                    permission.UPDATE_DEVICE_STATS, null);
+        // clients in the system process should have an attribution tag set
+        if (identity.getPid() == Process.myPid() && attributionTag == null) {
+            Log.w(TAG, "system location request with no attribution tag",
+                    new IllegalArgumentException());
         }
-        boolean hideFromAppOps = request.getHideFromAppOps();
-        if (hideFromAppOps) {
-            mContext.enforceCallingOrSelfPermission(
-                    permission.UPDATE_APP_OPS_STATS, null);
-        }
-        if (request.isLocationSettingsIgnored()) {
-            mContext.enforceCallingOrSelfPermission(
-                    permission.WRITE_SECURE_SETTINGS, null);
-        }
-        boolean callerHasLocationHardwarePermission =
-                mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
-                        == PERMISSION_GRANTED;
-        LocationRequest sanitizedRequest = createSanitizedRequest(request,
-                callerHasLocationHardwarePermission,
-                permissionLevel);
 
-        mLocationUsageLogger.logLocationApiUsage(
-                LocationStatsEnums.USAGE_STARTED,
-                LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
-                packageName, request, true, false,
-                /* geofence= */ null,
-                mAppForegroundHelper.isAppForeground(identity.getUid()));
+        request = validateAndSanitizeLocationRequest(request, permissionLevel);
 
-        synchronized (mLock) {
-            Receiver receiver = getReceiverLocked(Objects.requireNonNull(listener), identity,
-                    workSource, hideFromAppOps);
-            if (receiver != null) {
-                requestLocationUpdatesLocked(sanitizedRequest, receiver);
-            }
-        }
+        LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+        Preconditions.checkArgument(manager != null,
+                "provider \"" + request.getProvider() + "\" does not exist");
+
+        manager.registerLocationRequest(request, identity, permissionLevel, listener);
     }
 
     @Override
@@ -1976,248 +582,154 @@
             String packageName, String attributionTag) {
         CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
                 AppOpsManager.toReceiverId(pendingIntent));
-        int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
-        LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+        int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+                identity.getPid());
+        LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
                 PERMISSION_COARSE);
 
+        // clients in the system process must have an attribution tag set
+        Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
+
+        request = validateAndSanitizeLocationRequest(request, permissionLevel);
+
+        LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+        Preconditions.checkArgument(manager != null,
+                "provider \"" + request.getProvider() + "\" does not exist");
+
+        manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
+    }
+
+    private LocationRequest validateAndSanitizeLocationRequest(LocationRequest request,
+            @PermissionLevel int permissionLevel) {
+        Objects.requireNonNull(request.getProvider());
+
         WorkSource workSource = request.getWorkSource();
         if (workSource != null && !workSource.isEmpty()) {
             mContext.enforceCallingOrSelfPermission(
-                    permission.UPDATE_DEVICE_STATS, null);
+                    permission.UPDATE_DEVICE_STATS,
+                    "setting a work source requires " + permission.UPDATE_DEVICE_STATS);
         }
-        boolean hideFromAppOps = request.getHideFromAppOps();
-        if (hideFromAppOps) {
+        if (request.getHideFromAppOps()) {
             mContext.enforceCallingOrSelfPermission(
-                    permission.UPDATE_APP_OPS_STATS, null);
+                    permission.UPDATE_APP_OPS_STATS,
+                    "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
         }
         if (request.isLocationSettingsIgnored()) {
             mContext.enforceCallingOrSelfPermission(
-                    permission.WRITE_SECURE_SETTINGS, null);
-        }
-        boolean callerHasLocationHardwarePermission =
-                mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
-                        == PERMISSION_GRANTED;
-        LocationRequest sanitizedRequest = createSanitizedRequest(request,
-                callerHasLocationHardwarePermission,
-                permissionLevel);
-
-        mLocationUsageLogger.logLocationApiUsage(
-                LocationStatsEnums.USAGE_STARTED,
-                LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
-                packageName, request, true, false,
-                /* geofence= */ null,
-                mAppForegroundHelper.isAppForeground(identity.getUid()));
-
-        synchronized (mLock) {
-            Receiver receiver = getReceiverLocked(Objects.requireNonNull(pendingIntent), identity,
-                    workSource, hideFromAppOps);
-            if (receiver != null) {
-                requestLocationUpdatesLocked(sanitizedRequest, receiver);
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver) {
-        String provider = request.getProvider();
-
-        LocationProviderManager manager = getLocationProviderManager(provider);
-        if (manager == null) {
-            throw new IllegalArgumentException("provider doesn't exist: " + provider);
+                    permission.WRITE_SECURE_SETTINGS,
+                    "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
         }
 
-        UpdateRecord record = new UpdateRecord(provider, request, receiver);
-
-        UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, record);
-        if (oldRecord != null) {
-            oldRecord.disposeLocked(false);
+        LocationRequest sanitized = new LocationRequest(request);
+        if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE) != PERMISSION_GRANTED) {
+            sanitized.setLowPowerMode(false);
         }
-
-        long identity = Binder.clearCallingIdentity();
-        try {
-            int userId = UserHandle.getUserId(receiver.mCallerIdentity.getUid());
-            if (!manager.isEnabled(userId) && !isSettingsExempt(record)) {
-                // Notify the listener that updates are currently disabled - but only if the request
-                // does not ignore location settings
-                receiver.callProviderEnabledLocked(provider, false, request);
+        if (permissionLevel < PERMISSION_FINE) {
+            switch (sanitized.getQuality()) {
+                case LocationRequest.ACCURACY_FINE:
+                    sanitized.setQuality(LocationRequest.ACCURACY_BLOCK);
+                    break;
+                case LocationRequest.POWER_HIGH:
+                    sanitized.setQuality(LocationRequest.POWER_LOW);
+                    break;
             }
 
-            applyRequirementsLocked(provider);
-
-            // Update the monitoring here just in case multiple location requests were added to the
-            // same receiver (this request may be high power and the initial might not have been).
-            receiver.updateMonitoring(true);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            if (sanitized.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
+                sanitized.setInterval(FASTEST_COARSE_INTERVAL_MS);
+            }
+            if (sanitized.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
+                sanitized.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
+            }
         }
+        if (sanitized.getFastestInterval() > sanitized.getInterval()) {
+            sanitized.setFastestInterval(request.getInterval());
+        }
+        if (sanitized.getWorkSource() != null) {
+            if (sanitized.getWorkSource().isEmpty()) {
+                sanitized.setWorkSource(null);
+            } else if (sanitized.getWorkSource().getPackageName(0) == null) {
+                Log.w(TAG, "received (and ignoring) illegal worksource with no package name");
+                sanitized.setWorkSource(null);
+            } else {
+                List<WorkChain> workChains = sanitized.getWorkSource().getWorkChains();
+                if (workChains != null && !workChains.isEmpty() && workChains.get(
+                        0).getAttributionTag() == null) {
+                    Log.w(TAG,
+                            "received (and ignoring) illegal worksource with no attribution tag");
+                    sanitized.setWorkSource(null);
+                }
+            }
+        }
+
+        return sanitized;
     }
 
     @Override
     public void unregisterLocationListener(ILocationListener listener) {
-        synchronized (mLock) {
-            Receiver receiver = getReceiverLocked(Objects.requireNonNull(listener), null, null,
-                    false);
-            if (receiver != null) {
-                removeUpdatesLocked(receiver);
-            }
+        for (LocationProviderManager manager : mProviderManagers) {
+            manager.unregisterLocationRequest(listener);
         }
     }
 
     @Override
     public void unregisterLocationPendingIntent(PendingIntent pendingIntent) {
-        synchronized (mLock) {
-            Receiver receiver = getReceiverLocked(Objects.requireNonNull(pendingIntent), null, null,
-                    false);
-            if (receiver != null) {
-                removeUpdatesLocked(receiver);
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void removeUpdatesLocked(Receiver receiver) {
-        if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
-
-        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
-            receiver.unlinkFromListenerDeathNotificationLocked(
-                    receiver.getListener().asBinder());
-            receiver.clearPendingBroadcastsLocked();
-        }
-
-        receiver.updateMonitoring(false);
-
-        // Record which providers were associated with this listener
-        HashSet<String> providers = new HashSet<>();
-        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
-        if (oldRecords != null) {
-            // Call dispose() on the obsolete update records.
-            for (UpdateRecord record : oldRecords.values()) {
-                // Update statistics for historical location requests by package/provider
-                record.disposeLocked(false);
-            }
-            // Accumulate providers
-            providers.addAll(oldRecords.keySet());
-        }
-
-        // update provider
-        for (String provider : providers) {
-            applyRequirementsLocked(provider);
+        for (LocationProviderManager manager : mProviderManagers) {
+            manager.unregisterLocationRequest(pendingIntent);
         }
     }
 
     @Override
     public Location getLastLocation(LocationRequest request, String packageName,
             String attributionTag) {
-        // unsafe is ok because app ops will verify the package name
-        CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,   attributionTag);
-        int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
-        LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+        int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+                identity.getPid());
+        LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
                 PERMISSION_COARSE);
 
-        if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
-                identity.getPackageName())) {
-            return null;
-        }
-        if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
+        // clients in the system process must have an attribution tag set
+        Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
+
+        request = validateAndSanitizeLocationRequest(request, permissionLevel);
+
+        LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+        if (manager == null) {
             return null;
         }
 
-        synchronized (mLock) {
-            LocationProviderManager manager = getLocationProviderManager(request.getProvider());
-            if (manager == null) {
-                return null;
-            }
-            if (!manager.isEnabled(identity.getUserId()) && !request.isLocationSettingsIgnored()) {
-                return null;
-            }
+        Location location = manager.getLastLocation(request, identity, permissionLevel);
 
-            // appops check should always be right before delivery
-            if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
-                    identity)) {
-                return null;
-            }
-
-            Location location = manager.getLastLocation(identity.getUserId(), permissionLevel);
-
-            // make a defensive copy - the client could be in the same process as us
-            return location != null ? new Location(location) : null;
+        // lastly - note app ops
+        if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
+                identity)) {
+            return null;
         }
+
+        return location;
     }
 
     @Override
     public void getCurrentLocation(LocationRequest request,
-            ICancellationSignal remoteCancellationSignal, ILocationCallback callback,
+            ICancellationSignal cancellationTransport, ILocationCallback consumer,
             String packageName, String attributionTag, String listenerId) {
-        // unsafe is ok because app ops will verify the package name
-        CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag,
+        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
                 listenerId);
-        int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
-        LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+        int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+                identity.getPid());
+        LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
                 PERMISSION_COARSE);
 
-        request = createSanitizedRequest(request, false, permissionLevel);
-        request.setNumUpdates(1);
-        if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
-            request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
-        }
+        // clients in the system process must have an attribution tag set
+        Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
 
-        GetCurrentLocationTransport transport = new GetCurrentLocationTransport(callback);
+        request = validateAndSanitizeLocationRequest(request, permissionLevel);
 
-        if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
-                identity.getPackageName())) {
-            transport.deliverResult(null);
-            return;
-        }
-        if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
-            transport.deliverResult(null);
-            return;
-        }
+        LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+        Preconditions.checkArgument(manager != null,
+                "provider \"" + request.getProvider() + "\" does not exist");
 
-        Location lastLocation;
-        synchronized (mLock) {
-            LocationProviderManager manager = getLocationProviderManager(request.getProvider());
-            if (manager == null) {
-                transport.deliverResult(null);
-                return;
-            }
-            if (!manager.isEnabled(identity.getUserId()) && !request.isLocationSettingsIgnored()) {
-                transport.deliverResult(null);
-                return;
-            }
-
-            lastLocation = manager.getLastLocation(identity.getUserId(), permissionLevel);
-        }
-
-        if (lastLocation != null) {
-            long locationAgeMs = NANOSECONDS.toMillis(
-                    SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
-
-            if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
-                // appops check should always be right before delivery
-                if (mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
-                        identity)) {
-                    transport.deliverResult(lastLocation);
-                } else {
-                    transport.deliverResult(null);
-                }
-                return;
-            }
-
-            if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())) {
-                if (locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
-                    // not allowed to request new locations, so we can't return anything
-                    transport.deliverResult(null);
-                    return;
-                }
-            }
-        }
-
-        registerLocationListener(request, transport, packageName, attributionTag, listenerId);
-        CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
-                remoteCancellationSignal);
-        if (cancellationSignal != null) {
-            cancellationSignal.setOnCancelListener(() -> unregisterLocationListener(transport));
-        }
+        manager.getCurrentLocation(request, identity, permissionLevel, cancellationTransport,
+                consumer);
     }
 
     @Override
@@ -2228,8 +740,13 @@
                 return null;
             }
 
-            Location location = gpsManager.getLastLocation(UserHandle.getCallingUserId(),
-                    PERMISSION_FINE);
+            // create a location request that works in almost all circumstances
+            LocationRequest request = LocationRequest.createFromDeprecatedProvider(GPS_PROVIDER, 0,
+                    0, true);
+
+            // use our own identity rather than the caller
+            CallerIdentity identity = CallerIdentity.fromContext(mContext);
+            Location location = gpsManager.getLastLocation(request, identity, PERMISSION_FINE);
             if (location == null) {
                 return null;
             }
@@ -2248,11 +765,9 @@
         Preconditions.checkArgument(location.isComplete());
 
         int userId = UserHandle.getCallingUserId();
-        synchronized (mLock) {
-            LocationProviderManager manager = getLocationProviderManager(location.getProvider());
-            if (manager != null && manager.isEnabled(userId)) {
-                manager.injectLastLocation(Objects.requireNonNull(location), userId);
-            }
+        LocationProviderManager manager = getLocationProviderManager(location.getProvider());
+        if (manager != null && manager.isEnabled(userId)) {
+            manager.injectLastLocation(Objects.requireNonNull(location), userId);
         }
     }
 
@@ -2357,12 +872,11 @@
                     Objects.requireNonNull(command), extras);
         }
 
-        mLocationUsageLogger.logLocationApiUsage(
+        mInjector.getLocationUsageLogger().logLocationApiUsage(
                 LocationStatsEnums.USAGE_STARTED,
                 LocationStatsEnums.API_SEND_EXTRA_COMMAND,
                 provider);
-
-        mLocationUsageLogger.logLocationApiUsage(
+        mInjector.getLocationUsageLogger().logLocationApiUsage(
                 LocationStatsEnums.USAGE_ENDED,
                 LocationStatsEnums.API_SEND_EXTRA_COMMAND,
                 provider);
@@ -2385,7 +899,7 @@
             if (provider != null && !provider.equals(manager.getName())) {
                 continue;
             }
-            CallerIdentity identity = manager.getProviderIdentity();
+            CallerIdentity identity = manager.getIdentity();
             if (identity == null) {
                 continue;
             }
@@ -2406,7 +920,7 @@
             return Collections.emptyList();
         }
 
-        CallerIdentity identity = manager.getProviderIdentity();
+        CallerIdentity identity = manager.getIdentity();
         if (identity == null) {
             return Collections.emptyList();
         }
@@ -2454,164 +968,26 @@
 
         mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null);
 
-        invalidateLocalLocationEnabledCaches();
-        mSettingsHelper.setLocationEnabled(enabled, userId);
+        LocationManager.invalidateLocalLocationEnabledCaches();
+        mInjector.getSettingsHelper().setLocationEnabled(enabled, userId);
     }
 
     @Override
     public boolean isLocationEnabledForUser(int userId) {
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, false, "isLocationEnabledForUser", null);
-        return mSettingsHelper.isLocationEnabled(userId);
+        return mInjector.getSettingsHelper().isLocationEnabled(userId);
     }
 
     @Override
     public boolean isProviderEnabledForUser(String provider, int userId) {
-        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+        // fused provider is accessed indirectly via criteria rather than the provider-based APIs,
         // so we discourage its use
         if (FUSED_PROVIDER.equals(provider)) return false;
 
         return mLocalService.isProviderEnabledForUser(provider, userId);
     }
 
-    @GuardedBy("mLock")
-    private static boolean shouldBroadcastSafeLocked(
-            Location loc, Location lastLoc, UpdateRecord record, long now) {
-        // Always broadcast the first update
-        if (lastLoc == null) {
-            return true;
-        }
-
-        // Check whether sufficient time has passed
-        long minTime = record.mRealRequest.getFastestInterval();
-        long deltaMs = NANOSECONDS.toMillis(
-                loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos());
-        if (deltaMs < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
-            return false;
-        }
-
-        // Check whether sufficient distance has been traveled
-        double minDistance = record.mRealRequest.getSmallestDisplacement();
-        if (minDistance > 0.0) {
-            if (loc.distanceTo(lastLoc) <= minDistance) {
-                return false;
-            }
-        }
-
-        // Check whether sufficient number of udpates is left
-        if (record.mRealRequest.getNumUpdates() <= 0) {
-            return false;
-        }
-
-        // Check whether the expiry date has passed
-        return record.mExpirationRealtimeMs >= now;
-    }
-
-    @GuardedBy("mLock")
-    private void handleLocationChangedLocked(LocationProviderManager manager, Location fineLocation,
-            Location coarseLocation) {
-        if (!mProviderManagers.contains(manager)) {
-            Log.w(TAG, "received location from unknown provider: " + manager.getName());
-            return;
-        }
-
-        // notify passive provider
-        if (manager != mPassiveManager) {
-            mPassiveManager.updateLocation(fineLocation);
-        }
-
-        long now = SystemClock.elapsedRealtime();
-
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
-        if (records == null || records.size() == 0) return;
-
-        ArrayList<Receiver> deadReceivers = null;
-        ArrayList<UpdateRecord> deadUpdateRecords = null;
-
-        // Broadcast location to all listeners
-        for (UpdateRecord r : records) {
-            Receiver receiver = r.mReceiver;
-            CallerIdentity identity = receiver.mCallerIdentity;
-            boolean receiverDead = false;
-
-
-            if (!manager.isEnabled(identity.getUserId()) && !isSettingsExempt(r)) {
-                continue;
-            }
-
-            if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())
-                    && !mLocalService.isProvider(null, identity)) {
-                continue;
-            }
-
-            if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
-                    identity.getPackageName())) {
-                continue;
-            }
-
-            int permissionLevel = r.mRequest.isCoarse() ? PERMISSION_COARSE : PERMISSION_FINE;
-
-            Location location;
-            switch (permissionLevel) {
-                case PERMISSION_COARSE:
-                    location = coarseLocation;
-                    break;
-                case PERMISSION_FINE:
-                    location = fineLocation;
-                    break;
-                default:
-                    throw new AssertionError();
-            }
-
-            if (shouldBroadcastSafeLocked(location, r.mLastFixBroadcast, r, now)) {
-                r.mLastFixBroadcast = location;
-
-                // appops check should always be right before delivery
-                if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
-                        receiver.mCallerIdentity)) {
-                    continue;
-                }
-
-                if (!receiver.callLocationChangedLocked(location, r.mRequest)) {
-                    receiverDead = true;
-                }
-                r.mRealRequest.decrementNumUpdates();
-            }
-
-            // track expired records
-            if (r.mRealRequest.getNumUpdates() <= 0 || r.mExpirationRealtimeMs < now) {
-                if (deadUpdateRecords == null) {
-                    deadUpdateRecords = new ArrayList<>();
-                }
-                deadUpdateRecords.add(r);
-            }
-            // track dead receivers
-            if (receiverDead) {
-                if (deadReceivers == null) {
-                    deadReceivers = new ArrayList<>();
-                }
-                if (!deadReceivers.contains(receiver)) {
-                    deadReceivers.add(receiver);
-                }
-            }
-        }
-
-        // remove dead records and receivers outside the loop
-        if (deadReceivers != null) {
-            for (Receiver receiver : deadReceivers) {
-                removeUpdatesLocked(receiver);
-            }
-        }
-        if (deadUpdateRecords != null) {
-            for (UpdateRecord r : deadUpdateRecords) {
-                r.disposeLocked(true);
-            }
-            applyRequirementsLocked(manager);
-        }
-    }
-
-    // Geocoder
-
     @Override
     public boolean geocoderIsPresent() {
         return mGeocodeProvider != null;
@@ -2637,7 +1013,6 @@
             double lowerLeftLatitude, double lowerLeftLongitude,
             double upperRightLatitude, double upperRightLongitude, int maxResults,
             GeocoderParams params, IGeocodeListener listener) {
-
         if (mGeocodeProvider != null) {
             mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
                     lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
@@ -2651,35 +1026,24 @@
         }
     }
 
-    // Mock Providers
-
     @Override
     public void addTestProvider(String provider, ProviderProperties properties,
             String packageName, String attributionTag) {
         // unsafe is ok because app ops will verify the package name
-        CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
-                attributionTag);
-        if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+        CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
+        if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
             return;
         }
 
-        synchronized (mLock) {
-            LocationProviderManager manager = getLocationProviderManager(provider);
-            if (manager == null) {
-                manager = new LocationProviderManager(provider);
-                mProviderManagers.add(manager);
-            }
-
-            manager.setMockProvider(new MockProvider(properties, identity));
-        }
+        getOrAddLocationProviderManager(provider).setMockProvider(
+                new MockProvider(properties, identity));
     }
 
     @Override
     public void removeTestProvider(String provider, String packageName, String attributionTag) {
         // unsafe is ok because app ops will verify the package name
-        CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
-                attributionTag);
-        if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+        CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
+        if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
             return;
         }
 
@@ -2691,7 +1055,7 @@
 
             manager.setMockProvider(null);
             if (!manager.hasProvider()) {
-                mProviderManagers.remove(manager);
+                removeLocationProviderManager(manager);
             }
         }
     }
@@ -2702,7 +1066,7 @@
         // unsafe is ok because app ops will verify the package name
         CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
                 attributionTag);
-        if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+        if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
             return;
         }
 
@@ -2723,7 +1087,7 @@
         // unsafe is ok because app ops will verify the package name
         CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
                 attributionTag);
-        if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+        if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
             return;
         }
 
@@ -2777,57 +1141,32 @@
 
         ipw.println("User Info:");
         ipw.increaseIndent();
-        mUserInfoHelper.dump(fd, ipw, args);
+        mInjector.getUserInfoHelper().dump(fd, ipw, args);
         ipw.decreaseIndent();
 
         ipw.println("Location Settings:");
         ipw.increaseIndent();
-        mSettingsHelper.dump(fd, ipw, args);
+        mInjector.getSettingsHelper().dump(fd, ipw, args);
         ipw.decreaseIndent();
 
+        ipw.println("Historical Records by Provider:");
+        ipw.increaseIndent();
+        TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>(
+                mInjector.getLocationRequestStatistics().statistics);
+        for (Map.Entry<PackageProviderKey, PackageStatistics> entry
+                : sorted.entrySet()) {
+            ipw.println(entry.getKey() + ": " + entry.getValue());
+        }
+        ipw.decreaseIndent();
+
+        mInjector.getLocationRequestStatistics().history.dump(ipw);
+
         synchronized (mLock) {
-            ipw.println("Battery Saver Location Mode: "
-                    + locationPowerSaveModeToString(mBatterySaverMode));
-
-            if (dumpFilter == null) {
-                ipw.println("Location Listeners:");
-                ipw.increaseIndent();
-                for (Receiver receiver : mReceivers.values()) {
-                    ipw.println(receiver);
-                }
-                ipw.decreaseIndent();
-
-                ipw.println("Active Records by Provider:");
-                ipw.increaseIndent();
-                for (Map.Entry<String, ArrayList<UpdateRecord>> entry :
-                        mRecordsByProvider.entrySet()) {
-                    ipw.println(entry.getKey() + ":");
-                    ipw.increaseIndent();
-                    for (UpdateRecord record : entry.getValue()) {
-                        ipw.println(record);
-                    }
-                    ipw.decreaseIndent();
-                }
-                ipw.decreaseIndent();
-
-            ipw.println("Historical Records by Provider:");
-            ipw.increaseIndent();
-            TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>(
-                    mRequestStatistics.statistics);
-            for (Map.Entry<PackageProviderKey, PackageStatistics> entry
-                    : sorted.entrySet()) {
-                ipw.println(entry.getKey() + ": " + entry.getValue());
-            }
-            ipw.decreaseIndent();
-
-                mRequestStatistics.history.dump(ipw);
-
-                if (mExtraLocationControllerPackage != null) {
-                    ipw.println(
-                            "Location Controller Extra Package: " + mExtraLocationControllerPackage
-                                    + (mExtraLocationControllerPackageEnabled ? " [enabled]"
-                                    : "[disabled]"));
-                }
+            if (mExtraLocationControllerPackage != null) {
+                ipw.println(
+                        "Location Controller Extra Package: " + mExtraLocationControllerPackage
+                                + (mExtraLocationControllerPackageEnabled ? " [enabled]"
+                                : "[disabled]"));
             }
         }
 
@@ -2857,47 +1196,6 @@
         }
     }
 
-    private class GetCurrentLocationTransport extends ILocationListener.Stub {
-
-        private final Executor mExecutor;
-        private final ILocationCallback mCallback;
-
-        GetCurrentLocationTransport(ILocationCallback callback) {
-            mExecutor = FgThread.getExecutor();
-            mCallback = callback;
-        }
-
-        @Override
-        public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
-            mExecutor.execute(() -> {
-                deliverResult(location);
-                try {
-                    onCompleteCallback.sendResult(null);
-                } catch (RemoteException e) {
-                    e.rethrowFromSystemServer();
-                }
-            });
-            unregisterLocationListener(this);
-        }
-
-        @Override
-        public void onProviderEnabledChanged(String provider, boolean enabled)
-                throws RemoteException {
-            if (!enabled) {
-                deliverResult(null);
-                unregisterLocationListener(this);
-            }
-        }
-
-        public void deliverResult(@Nullable Location location) {
-            try {
-                mCallback.onLocation(location);
-            } catch (RemoteException e) {
-                // do nothing
-            }
-        }
-    }
-
     private class LocalService extends LocationManagerInternal {
 
         LocalService() {}
@@ -2916,17 +1214,28 @@
         }
 
         @Override
-        public boolean isProvider(String provider, CallerIdentity identity) {
-            for (LocationProviderManager manager : mProviderManagers) {
-                if (provider != null && !provider.equals(manager.getName())) {
-                    continue;
-                }
-                if (identity.equals(manager.getProviderIdentity())) {
-                    return true;
-                }
-            }
+        public void addProviderEnabledListener(String provider, ProviderEnabledListener listener) {
+            LocationProviderManager manager = Objects.requireNonNull(
+                    getLocationProviderManager(provider));
+            manager.addEnabledListener(listener);
+        }
 
-            return false;
+        @Override
+        public void removeProviderEnabledListener(String provider,
+                ProviderEnabledListener listener) {
+            LocationProviderManager manager = Objects.requireNonNull(
+                    getLocationProviderManager(provider));
+            manager.removeEnabledListener(listener);
+        }
+
+        @Override
+        public boolean isProvider(String provider, CallerIdentity identity) {
+            LocationProviderManager manager = getLocationProviderManager(provider);
+            if (manager == null) {
+                return false;
+            } else {
+                return identity.equals(manager.getIdentity());
+            }
         }
 
         @Override
@@ -2935,6 +1244,13 @@
                 mGnssManagerService.sendNiResponse(notifId, userResponse);
             }
         }
+
+        @Override
+        public void reportGnssBatchLocations(List<Location> locations) {
+            if (mGnssManagerService != null) {
+                mGnssManagerService.onReportLocation(locations);
+            }
+        }
     }
 
     private static class SystemInjector implements Injector {
diff --git a/services/core/java/com/android/server/location/LocationManagerServiceUtils.java b/services/core/java/com/android/server/location/LocationManagerServiceUtils.java
deleted file mode 100644
index b9d86c8..0000000
--- a/services/core/java/com/android/server/location/LocationManagerServiceUtils.java
+++ /dev/null
@@ -1,73 +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.location;
-
-import android.annotation.NonNull;
-import android.location.util.identity.CallerIdentity;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import java.util.NoSuchElementException;
-
-/**
- * Shared utilities for LocationManagerService and GnssManager.
- */
-public class LocationManagerServiceUtils {
-
-    /**
-     * Skeleton class of listener that can be linked to a binder.
-     */
-    public abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
-        protected final CallerIdentity mCallerIdentity;
-
-        LinkedListenerBase(@NonNull CallerIdentity callerIdentity) {
-            mCallerIdentity = callerIdentity;
-        }
-
-        @Override
-        public String toString() {
-            return mCallerIdentity.toString();
-        }
-
-        public CallerIdentity getCallerIdentity() {
-            return mCallerIdentity;
-        }
-
-        /**
-         * Link listener (i.e. callback) to a binder, so that it will be called upon binder's death.
-         */
-        public boolean linkToListenerDeathNotificationLocked(IBinder binder) {
-            try {
-                binder.linkToDeath(this, 0 /* flags */);
-                return true;
-            } catch (RemoteException e) {
-                return false;
-            }
-        }
-
-        /**
-         * Unlink death listener (i.e. callback) from binder.
-         */
-        public void unlinkFromListenerDeathNotificationLocked(IBinder binder) {
-            try {
-                binder.unlinkToDeath(this, 0 /* flags */);
-            } catch (NoSuchElementException e) {
-                // ignore
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
new file mode 100644
index 0000000..d4f8c7e
--- /dev/null
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -0,0 +1,1951 @@
+/*
+ * 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.location;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.WINDOW_EXACT;
+import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.KEY_LOCATION_CHANGED;
+import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
+import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
+import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
+import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+
+import static com.android.server.location.LocationManagerService.D;
+import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
+import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Criteria;
+import android.location.ILocationCallback;
+import android.location.ILocationListener;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
+import android.location.LocationRequest;
+import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.PowerManager.LocationPowerSaveMode;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.stats.location.LocationStatsEnums;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.EventLog;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.Preconditions;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.PendingIntentUtils;
+import com.android.server.location.LocationPermissions.PermissionLevel;
+import com.android.server.location.listeners.ListenerMultiplexer;
+import com.android.server.location.listeners.RemovableListenerRegistration;
+import com.android.server.location.util.AppForegroundHelper;
+import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
+import com.android.server.location.util.AppOpsHelper;
+import com.android.server.location.util.Injector;
+import com.android.server.location.util.LocationAttributionHelper;
+import com.android.server.location.util.LocationPermissionsHelper;
+import com.android.server.location.util.LocationPermissionsHelper.LocationPermissionsListener;
+import com.android.server.location.util.LocationPowerSaveModeHelper;
+import com.android.server.location.util.LocationPowerSaveModeHelper.LocationPowerSaveModeChangedListener;
+import com.android.server.location.util.LocationUsageLogger;
+import com.android.server.location.util.ScreenInteractiveHelper;
+import com.android.server.location.util.ScreenInteractiveHelper.ScreenInteractiveChangedListener;
+import com.android.server.location.util.SettingsHelper;
+import com.android.server.location.util.SettingsHelper.GlobalSettingChangedListener;
+import com.android.server.location.util.SettingsHelper.UserSettingChangedListener;
+import com.android.server.location.util.UserInfoHelper;
+import com.android.server.location.util.UserInfoHelper.UserListener;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+class LocationProviderManager extends
+        ListenerMultiplexer<Object, LocationRequest, LocationProviderManager.LocationTransport,
+                LocationProviderManager.Registration, ProviderRequest> implements
+        AbstractLocationProvider.Listener {
+
+    // fastest interval at which clients may receive coarse locations
+    public static final long FASTEST_COARSE_INTERVAL_MS = 10 * 60 * 1000;
+
+    private static final String WAKELOCK_TAG = "*location*";
+    private static final long WAKELOCK_TIMEOUT_MS = 30 * 1000;
+
+    // maximum interval to be considered "high power" request
+    private static final long MAX_HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
+
+    // maximum age of a location before it is no longer considered "current"
+    private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
+
+    // max timeout allowed for getting the current location
+    private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000;
+
+    // maximum jitter allowed for fastest interval evaluation
+    private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 100;
+
+    protected interface LocationTransport {
+
+        void deliverOnLocationChanged(Location location, @Nullable Runnable onCompleteCallback)
+                throws Exception;
+    }
+
+    protected interface ProviderTransport {
+
+        void deliverOnProviderEnabledChanged(String provider, boolean enabled) throws Exception;
+    }
+
+    protected static final class LocationListenerTransport implements LocationTransport,
+            ProviderTransport {
+
+        private final ILocationListener mListener;
+
+        protected LocationListenerTransport(ILocationListener listener) {
+            mListener = Objects.requireNonNull(listener);
+        }
+
+        @Override
+        public void deliverOnLocationChanged(Location location,
+                @Nullable Runnable onCompleteCallback)
+                throws RemoteException {
+            mListener.onLocationChanged(location,
+                    onCompleteCallback == null ? null : new IRemoteCallback.Stub() {
+                        @Override
+                        public void sendResult(Bundle data) {
+                            onCompleteCallback.run();
+                        }
+                    });
+        }
+
+        @Override
+        public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
+                throws RemoteException {
+            mListener.onProviderEnabledChanged(provider, enabled);
+        }
+    }
+
+    protected static final class LocationPendingIntentTransport implements LocationTransport,
+            ProviderTransport {
+
+        private final Context mContext;
+        private final PendingIntent mPendingIntent;
+
+        public LocationPendingIntentTransport(Context context, PendingIntent pendingIntent) {
+            mContext = context;
+            mPendingIntent = pendingIntent;
+        }
+
+        @Override
+        public void deliverOnLocationChanged(Location location,
+                @Nullable Runnable onCompleteCallback)
+                throws PendingIntent.CanceledException {
+            mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_LOCATION_CHANGED, location),
+                    onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
+                            : null, null, null,
+                    PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+        }
+
+        @Override
+        public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
+                throws PendingIntent.CanceledException {
+            mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_PROVIDER_ENABLED, enabled),
+                    null, null, null,
+                    PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+        }
+    }
+
+    protected static final class GetCurrentLocationTransport implements LocationTransport {
+
+        private final ILocationCallback mCallback;
+
+        protected GetCurrentLocationTransport(ILocationCallback callback) {
+            mCallback = Objects.requireNonNull(callback);
+        }
+
+        @Override
+        public void deliverOnLocationChanged(Location location,
+                @Nullable Runnable onCompleteCallback)
+                throws RemoteException {
+            // ILocationCallback doesn't currently support completion callbacks
+            Preconditions.checkState(onCompleteCallback == null);
+            mCallback.onLocation(location);
+        }
+    }
+
+    protected abstract class Registration extends
+            RemovableListenerRegistration<LocationRequest, LocationTransport> {
+
+        @PermissionLevel protected final int mPermissionLevel;
+        private final WorkSource mWorkSource;
+
+        // we cache these values because checking/calculating on the fly is more expensive
+        private boolean mPermitted;
+        private boolean mForeground;
+        @Nullable private LocationRequest mProviderLocationRequest;
+        private boolean mIsUsingHighPower;
+
+        protected Registration(LocationRequest request, CallerIdentity identity,
+                LocationTransport transport, @PermissionLevel int permissionLevel) {
+            super(TAG, Objects.requireNonNull(request), identity, transport);
+
+            Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
+            mPermissionLevel = permissionLevel;
+
+            if (request.getWorkSource() != null && !request.getWorkSource().isEmpty()) {
+                mWorkSource = request.getWorkSource();
+            } else {
+                mWorkSource = identity.addToWorkSource(null);
+            }
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected final void onRemovableListenerRegister() {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            if (D) {
+                Log.d(TAG, mName + " provider added registration from " + getIdentity() + " -> "
+                        + getRequest());
+            }
+
+            // initialization order is important as there are ordering dependencies
+            mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
+                    getIdentity());
+            mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid());
+            mProviderLocationRequest = calculateProviderLocationRequest();
+            mIsUsingHighPower = isUsingHighPower();
+
+            onProviderListenerRegister();
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected final void onRemovableListenerUnregister() {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            onProviderListenerUnregister();
+
+            if (D) {
+                Log.d(TAG, mName + " provider removed registration from " + getIdentity());
+            }
+        }
+
+        /**
+         * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
+         */
+        @GuardedBy("mLock")
+        protected void onProviderListenerRegister() {}
+
+        /**
+         * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
+         */
+        @GuardedBy("mLock")
+        protected void onProviderListenerUnregister() {}
+
+        @Override
+        protected final ListenerOperation<LocationTransport> onActive() {
+            if (!getRequest().getHideFromAppOps()) {
+                mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
+            }
+            onHighPowerUsageChanged();
+            return null;
+        }
+
+        @Override
+        protected final void onInactive() {
+            onHighPowerUsageChanged();
+            if (!getRequest().getHideFromAppOps()) {
+                mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
+            }
+        }
+
+        @Override
+        public final LocationRequest getRequest() {
+            return Objects.requireNonNull(mProviderLocationRequest);
+        }
+
+        public final boolean isForeground() {
+            return mForeground;
+        }
+
+        public final boolean isPermitted() {
+            return mPermitted;
+        }
+
+        @Override
+        protected final LocationProviderManager getOwner() {
+            return LocationProviderManager.this;
+        }
+
+        protected final WorkSource getWorkSource() {
+            return mWorkSource;
+        }
+
+        @GuardedBy("mLock")
+        private void onHighPowerUsageChanged() {
+            boolean isUsingHighPower = isUsingHighPower();
+            if (isUsingHighPower != mIsUsingHighPower) {
+                mIsUsingHighPower = isUsingHighPower;
+
+                if (!getRequest().getHideFromAppOps()) {
+                    if (mIsUsingHighPower) {
+                        mLocationAttributionHelper.reportHighPowerLocationStart(
+                                getIdentity(), getName(), getKey());
+                    } else {
+                        mLocationAttributionHelper.reportHighPowerLocationStop(
+                                getIdentity(), getName(), getKey());
+                    }
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        private boolean isUsingHighPower() {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            return isActive()
+                    && getRequest().getInterval() < MAX_HIGH_POWER_INTERVAL_MS
+                    && getProperties().mPowerRequirement == Criteria.POWER_HIGH;
+        }
+
+        @GuardedBy("mLock")
+        final boolean onLocationPermissionsChanged(String packageName) {
+            if (getIdentity().getPackageName().equals(packageName)) {
+                return onLocationPermissionsChanged();
+            }
+
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        final boolean onLocationPermissionsChanged(int uid) {
+            if (getIdentity().getUid() == uid) {
+                return onLocationPermissionsChanged();
+            }
+
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        private boolean onLocationPermissionsChanged() {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
+                    getIdentity());
+            if (permitted != mPermitted) {
+                if (D) {
+                    Log.v(TAG, mName + " provider package " + getIdentity().getPackageName()
+                            + " permitted = " + permitted);
+                }
+
+                mPermitted = permitted;
+                return true;
+            }
+
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        final boolean onForegroundChanged(int uid, boolean foreground) {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            if (getIdentity().getUid() == uid && foreground != mForeground) {
+                if (D) {
+                    Log.v(TAG, mName + " provider uid " + uid + " foreground = " + foreground);
+                }
+
+                mForeground = foreground;
+
+                // note that onProviderLocationRequestChanged() is always called
+                return onProviderLocationRequestChanged()
+                        || mLocationPowerSaveModeHelper.getLocationPowerSaveMode()
+                        == LOCATION_MODE_FOREGROUND_ONLY;
+            }
+
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        final boolean onProviderLocationRequestChanged() {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            LocationRequest newRequest = calculateProviderLocationRequest();
+            if (!mProviderLocationRequest.equals(newRequest)) {
+                LocationRequest oldRequest = mProviderLocationRequest;
+                mProviderLocationRequest = newRequest;
+                onHighPowerUsageChanged();
+                updateService();
+
+                // if location settings ignored has changed then the active state may have changed
+                return oldRequest.isLocationSettingsIgnored()
+                        != newRequest.isLocationSettingsIgnored();
+            }
+
+            return false;
+        }
+
+        private LocationRequest calculateProviderLocationRequest() {
+            LocationRequest newRequest = new LocationRequest(super.getRequest());
+
+            if (newRequest.isLocationSettingsIgnored()) {
+                // if we are not currently allowed use location settings ignored, disable it
+                if (!mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
+                        getIdentity().getPackageName()) && !mLocationManagerInternal.isProvider(
+                        null, getIdentity())) {
+                    newRequest.setLocationSettingsIgnored(false);
+                }
+            }
+
+            if (!newRequest.isLocationSettingsIgnored() && !isThrottlingExempt()) {
+                // throttle in the background
+                if (!mForeground) {
+                    newRequest.setInterval(Math.max(newRequest.getInterval(),
+                            mSettingsHelper.getBackgroundThrottleIntervalMs()));
+                }
+            }
+
+            return newRequest;
+        }
+
+        private boolean isThrottlingExempt() {
+            if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
+                    getIdentity().getPackageName())) {
+                return true;
+            }
+
+            return mLocationManagerInternal.isProvider(null, getIdentity());
+        }
+
+        @Nullable
+        abstract ListenerOperation<LocationTransport> acceptLocationChange(Location fineLocation);
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append(getIdentity());
+
+            ArraySet<String> flags = new ArraySet<>(2);
+            if (!isForeground()) {
+                flags.add("bg");
+            }
+            if (!isPermitted()) {
+                flags.add("na");
+            }
+            if (!flags.isEmpty()) {
+                builder.append(" ").append(flags);
+            }
+
+            if (mPermissionLevel == PERMISSION_COARSE) {
+                builder.append(" (COARSE)");
+            }
+
+            builder.append(" ").append(getRequest());
+            return builder.toString();
+        }
+    }
+
+    protected abstract class LocationRegistration extends Registration implements
+            AlarmManager.OnAlarmListener, ProviderEnabledListener {
+
+        private final PowerManager.WakeLock mWakeLock;
+
+        private volatile ProviderTransport mProviderTransport;
+        @Nullable private Location mLastLocation = null;
+        private int mNumLocationsDelivered = 0;
+        private long mExpirationRealtimeMs = Long.MAX_VALUE;
+
+        protected <TTransport extends LocationTransport & ProviderTransport> LocationRegistration(
+                LocationRequest request, CallerIdentity identity, TTransport transport,
+                @PermissionLevel int permissionLevel) {
+            super(request, identity, transport, permissionLevel);
+            mProviderTransport = transport;
+            mWakeLock = Objects.requireNonNull(mContext.getSystemService(PowerManager.class))
+                    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+            mWakeLock.setReferenceCounted(true);
+            mWakeLock.setWorkSource(getWorkSource());
+        }
+
+        @Override
+        protected void onListenerUnregister() {
+            mProviderTransport = null;
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected final void onProviderListenerRegister() {
+            mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
+                    SystemClock.elapsedRealtime());
+
+            // add alarm for expiration
+            if (mExpirationRealtimeMs < SystemClock.elapsedRealtime()) {
+                remove();
+            } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+                AlarmManager alarmManager = Objects.requireNonNull(
+                        mContext.getSystemService(AlarmManager.class));
+                alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
+                        0, this, FgThread.getHandler(), getWorkSource());
+            }
+
+            // start listening for provider enabled/disabled events
+            addEnabledListener(this);
+
+            onLocationListenerRegister();
+
+            // if the provider is currently disabled, let the client know immediately
+            int userId = getIdentity().getUserId();
+            if (!isEnabled(userId)) {
+                onProviderEnabledChanged(mName, userId, false);
+            }
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected final void onProviderListenerUnregister() {
+            // stop listening for provider enabled/disabled events
+            removeEnabledListener(this);
+
+            // remove alarm for expiration
+            if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+                AlarmManager alarmManager = Objects.requireNonNull(
+                        mContext.getSystemService(AlarmManager.class));
+                alarmManager.cancel(this);
+            }
+
+            onLocationListenerUnregister();
+        }
+
+        /**
+         * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
+         */
+        @GuardedBy("mLock")
+        protected void onLocationListenerRegister() {}
+
+        /**
+         * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
+         */
+        @GuardedBy("mLock")
+        protected void onLocationListenerUnregister() {}
+
+        @Override
+        public void onAlarm() {
+            if (D) {
+                Log.d(TAG, "removing " + getIdentity() + " from " + mName
+                        + " provider due to expiration at " + TimeUtils.formatRealtime(
+                        mExpirationRealtimeMs));
+            }
+
+            synchronized (mLock) {
+                remove();
+            }
+        }
+
+        @GuardedBy("mLock")
+        @Nullable
+        @Override
+        ListenerOperation<LocationTransport> acceptLocationChange(Location fineLocation) {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            // check expiration time - alarm is not guaranteed to go off at the right time,
+            // especially for short intervals
+            if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
+                remove();
+                return null;
+            }
+
+            Location location;
+            switch (mPermissionLevel) {
+                case PERMISSION_FINE:
+                    location = fineLocation;
+                    break;
+                case PERMISSION_COARSE:
+                    location = mLocationFudger.createCoarse(fineLocation);
+                    break;
+                default:
+                    // shouldn't be possible to have a client added without location permissions
+                    throw new AssertionError();
+            }
+
+            if (mLastLocation != null) {
+                // check fastest interval
+                long deltaMs = NANOSECONDS.toMillis(
+                        location.getElapsedRealtimeNanos()
+                                - mLastLocation.getElapsedRealtimeNanos());
+                if (deltaMs < getRequest().getFastestInterval() - MAX_FASTEST_INTERVAL_JITTER_MS) {
+                    return null;
+                }
+
+                // check smallest displacement
+                double smallestDisplacement = getRequest().getSmallestDisplacement();
+                if (smallestDisplacement > 0.0 && location.distanceTo(mLastLocation)
+                        <= smallestDisplacement) {
+                    return null;
+                }
+            }
+
+            // note app ops
+            if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
+                    getIdentity())) {
+                if (D) {
+                    Log.w(TAG, "noteOp denied for " + getIdentity());
+                }
+                return null;
+            }
+
+            // update last location
+            mLastLocation = location;
+
+            return new ListenerOperation<LocationTransport>() {
+                @Override
+                public void onPreExecute() {
+                    // don't acquire a wakelock for mock locations to prevent abuse
+                    if (!location.isFromMockProvider()) {
+                        mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+                    }
+                }
+
+                @Override
+                public void operate(LocationTransport listener) throws Exception {
+                    // if delivering to the same process, make a copy of the location first (since
+                    // location is mutable)
+                    Location deliveryLocation;
+                    if (getIdentity().getPid() == Process.myPid()) {
+                        deliveryLocation = new Location(location);
+                    } else {
+                        deliveryLocation = location;
+                    }
+
+                    listener.deliverOnLocationChanged(deliveryLocation,
+                            location.isFromMockProvider() ? null : mWakeLock::release);
+                }
+
+                @Override
+                public void onPostExecute(boolean success) {
+                    if (!success && !location.isFromMockProvider()) {
+                        mWakeLock.release();
+                    }
+
+                    if (success) {
+                        // check num updates - if successful then this function will always be run
+                        // from the same thread, and no additional synchronization is necessary
+                        boolean remove = ++mNumLocationsDelivered >= getRequest().getNumUpdates();
+                        if (remove) {
+                            if (D) {
+                                Log.d(TAG, "removing " + getIdentity() + " from " + mName
+                                        + " provider due to number of updates");
+                            }
+
+                            synchronized (mLock) {
+                                remove();
+                            }
+                        }
+                    }
+                }
+            };
+        }
+
+        @Override
+        public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+            Preconditions.checkState(mName.equals(provider));
+
+            if (userId != getIdentity().getUserId()) {
+                return;
+            }
+
+            // we choose not to hold a wakelock for provider enabled changed events
+            executeSafely(getExecutor(), () -> mProviderTransport,
+                    listener -> listener.deliverOnProviderEnabledChanged(mName, enabled));
+        }
+    }
+
+    protected final class LocationListenerRegistration extends LocationRegistration implements
+            IBinder.DeathRecipient {
+
+        protected LocationListenerRegistration(LocationRequest request, CallerIdentity identity,
+                LocationListenerTransport transport, @PermissionLevel int permissionLevel) {
+            super(request, identity, transport, permissionLevel);
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected void onLocationListenerRegister() {
+            try {
+                ((IBinder) getKey()).linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                remove();
+            }
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected void onLocationListenerUnregister() {
+            ((IBinder) getKey()).unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            try {
+                if (D) {
+                    Log.d(TAG, mName + " provider client died: " + getIdentity());
+                }
+
+                synchronized (mLock) {
+                    remove();
+                }
+            } catch (RuntimeException e) {
+                // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
+                // ensure the crash is seen
+                throw new AssertionError(e);
+            }
+        }
+    }
+
+    protected final class LocationPendingIntentRegistration extends LocationRegistration implements
+            PendingIntent.CancelListener {
+
+        protected LocationPendingIntentRegistration(LocationRequest request,
+                CallerIdentity identity, LocationPendingIntentTransport transport,
+                @PermissionLevel int permissionLevel) {
+            super(request, identity, transport, permissionLevel);
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected void onLocationListenerRegister() {
+            ((PendingIntent) getKey()).registerCancelListener(this);
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected void onLocationListenerUnregister() {
+            ((PendingIntent) getKey()).unregisterCancelListener(this);
+        }
+
+        @Override
+        public void onCancelled(PendingIntent intent) {
+            synchronized (mLock) {
+                remove();
+            }
+        }
+    }
+
+    protected final class GetCurrentLocationListenerRegistration extends Registration implements
+            IBinder.DeathRecipient, ProviderEnabledListener, AlarmManager.OnAlarmListener {
+
+        private volatile LocationTransport mTransport;
+
+        private long mExpirationRealtimeMs = Long.MAX_VALUE;
+
+        protected GetCurrentLocationListenerRegistration(LocationRequest request,
+                CallerIdentity identity, LocationTransport transport, int permissionLevel) {
+            super(request, identity, transport, permissionLevel);
+            mTransport = transport;
+        }
+
+        @GuardedBy("mLock")
+        void deliverLocation(@Nullable Location location) {
+            executeSafely(getExecutor(), () -> mTransport, acceptLocationChange(location));
+        }
+
+        @Override
+        protected void onListenerUnregister() {
+            mTransport = null;
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected void onProviderListenerRegister() {
+            mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
+                    SystemClock.elapsedRealtime());
+
+            // add alarm for expiration
+            if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+                AlarmManager alarmManager = Objects.requireNonNull(
+                        mContext.getSystemService(AlarmManager.class));
+                alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
+                        0, this, FgThread.getHandler(), getWorkSource());
+            }
+
+            try {
+                ((IBinder) getKey()).linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                remove();
+            }
+
+            // start listening for provider enabled/disabled events
+            addEnabledListener(this);
+
+            // if the provider is currently disabled fail immediately
+            int userId = getIdentity().getUserId();
+            if (!getRequest().isLocationSettingsIgnored() && !isEnabled(userId)) {
+                deliverLocation(null);
+            }
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        protected void onProviderListenerUnregister() {
+            // stop listening for provider enabled/disabled events
+            removeEnabledListener(this);
+
+            // remove alarm for expiration
+            if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+                AlarmManager alarmManager = Objects.requireNonNull(
+                        mContext.getSystemService(AlarmManager.class));
+                alarmManager.cancel(this);
+            }
+
+            ((IBinder) getKey()).unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void onAlarm() {
+            if (D) {
+                Log.d(TAG, "removing " + getIdentity() + " from " + mName
+                        + " provider due to expiration at " + TimeUtils.formatRealtime(
+                        mExpirationRealtimeMs));
+            }
+
+            synchronized (mLock) {
+                deliverLocation(null);
+            }
+        }
+
+        @GuardedBy("mLock")
+        @Nullable
+        @Override
+        ListenerOperation<LocationTransport> acceptLocationChange(@Nullable Location fineLocation) {
+            if (Build.IS_DEBUGGABLE) {
+                Preconditions.checkState(Thread.holdsLock(mLock));
+            }
+
+            // lastly - note app ops
+            Location location;
+            if (fineLocation == null) {
+                location = null;
+            } else if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
+                    getIdentity())) {
+                if (D) {
+                    Log.w(TAG, "noteOp denied for " + getIdentity());
+                }
+                location = null;
+            } else {
+                switch (mPermissionLevel) {
+                    case PERMISSION_FINE:
+                        location = fineLocation;
+                        break;
+                    case PERMISSION_COARSE:
+                        location = mLocationFudger.createCoarse(fineLocation);
+                        break;
+                    default:
+                        // shouldn't be possible to have a client added without location permissions
+                        throw new AssertionError();
+                }
+            }
+
+            return listener -> {
+                // if delivering to the same process, make a copy of the location first (since
+                // location is mutable)
+                Location deliveryLocation = location;
+                if (getIdentity().getPid() == Process.myPid() && location != null) {
+                    deliveryLocation = new Location(location);
+                }
+
+                // we currently don't hold a wakelock for getCurrentLocation deliveries
+                listener.deliverOnLocationChanged(deliveryLocation, null);
+
+                synchronized (mLock) {
+                    remove();
+                }
+            };
+        }
+
+        @Override
+        public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+            Preconditions.checkState(mName.equals(provider));
+
+            if (userId != getIdentity().getUserId()) {
+                return;
+            }
+
+            // if the provider is disabled we give up on current location immediately
+            if (!getRequest().isLocationSettingsIgnored() && !enabled) {
+                synchronized (mLock) {
+                    deliverLocation(null);
+                }
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            try {
+                if (D) {
+                    Log.d(TAG, mName + " provider client died: " + getIdentity());
+                }
+
+                synchronized (mLock) {
+                    remove();
+                }
+            } catch (RuntimeException e) {
+                // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
+                // ensure the crash is seen
+                throw new AssertionError(e);
+            }
+        }
+    }
+
+    protected final Object mLock = new Object();
+
+    protected final String mName;
+    @Nullable private final PassiveLocationProviderManager mPassiveManager;
+
+    protected final Context mContext;
+
+    @GuardedBy("mLock")
+    private boolean mStarted;
+
+    // maps of user id to value
+    @GuardedBy("mLock")
+    private final SparseBooleanArray mEnabled; // null or not present means unknown
+    @GuardedBy("mLock")
+    private final SparseArray<LastLocation> mLastLocations;
+
+    @GuardedBy("mLock")
+    private final ArrayList<ProviderEnabledListener> mEnabledListeners;
+
+    protected final LocationManagerInternal mLocationManagerInternal;
+    protected final SettingsHelper mSettingsHelper;
+    protected final UserInfoHelper mUserInfoHelper;
+    protected final AppOpsHelper mAppOpsHelper;
+    protected final LocationPermissionsHelper mLocationPermissionsHelper;
+    protected final AppForegroundHelper mAppForegroundHelper;
+    protected final LocationPowerSaveModeHelper mLocationPowerSaveModeHelper;
+    protected final ScreenInteractiveHelper mScreenInteractiveHelper;
+    protected final LocationAttributionHelper mLocationAttributionHelper;
+    protected final LocationUsageLogger mLocationUsageLogger;
+    protected final LocationFudger mLocationFudger;
+    protected final LocationRequestStatistics mLocationRequestStatistics;
+
+    private final UserListener mUserChangedListener = this::onUserChanged;
+    private final UserSettingChangedListener mLocationEnabledChangedListener =
+            this::onLocationEnabledChanged;
+    private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
+            this::onBackgroundThrottlePackageWhitelistChanged;
+    private final UserSettingChangedListener mLocationPackageBlacklistChangedListener =
+            this::onLocationPackageBlacklistChanged;
+    private final LocationPermissionsListener mLocationPermissionsListener =
+            new LocationPermissionsListener() {
+                @Override
+                public void onLocationPermissionsChanged(String packageName) {
+                    LocationProviderManager.this.onLocationPermissionsChanged(packageName);
+                }
+
+                @Override
+                public void onLocationPermissionsChanged(int uid) {
+                    LocationProviderManager.this.onLocationPermissionsChanged(uid);
+                }
+            };
+    private final AppForegroundListener mAppForegroundChangedListener =
+            this::onAppForegroundChanged;
+    private final GlobalSettingChangedListener mBackgroundThrottleIntervalChangedListener =
+            this::onBackgroundThrottleIntervalChanged;
+    private final GlobalSettingChangedListener mIgnoreSettingsPackageWhitelistChangedListener =
+            this::onIgnoreSettingsWhitelistChanged;
+    private final LocationPowerSaveModeChangedListener mLocationPowerSaveModeChangedListener =
+            this::onLocationPowerSaveModeChanged;
+    private final ScreenInteractiveChangedListener mScreenInteractiveChangedListener =
+            this::onScreenInteractiveChanged;
+
+    // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
+    protected final MockableLocationProvider mProvider;
+
+    LocationProviderManager(Context context, Injector injector, String name,
+            @Nullable PassiveLocationProviderManager passiveManager) {
+        mContext = context;
+        mName = Objects.requireNonNull(name);
+        mPassiveManager = passiveManager;
+        mStarted = false;
+        mEnabled = new SparseBooleanArray(2);
+        mLastLocations = new SparseArray<>(2);
+
+        mEnabledListeners = new ArrayList<>();
+
+        mLocationManagerInternal = Objects.requireNonNull(
+                LocalServices.getService(LocationManagerInternal.class));
+        mSettingsHelper = injector.getSettingsHelper();
+        mUserInfoHelper = injector.getUserInfoHelper();
+        mAppOpsHelper = injector.getAppOpsHelper();
+        mLocationPermissionsHelper = injector.getLocationPermissionsHelper();
+        mAppForegroundHelper = injector.getAppForegroundHelper();
+        mLocationPowerSaveModeHelper = injector.getLocationPowerSaveModeHelper();
+        mScreenInteractiveHelper = injector.getScreenInteractiveHelper();
+        mLocationAttributionHelper = injector.getLocationAttributionHelper();
+        mLocationUsageLogger = injector.getLocationUsageLogger();
+        mLocationRequestStatistics = injector.getLocationRequestStatistics();
+        mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
+
+        // initialize last since this lets our reference escape
+        mProvider = new MockableLocationProvider(mLock, this);
+    }
+
+    public void startManager() {
+        synchronized (mLock) {
+            mStarted = true;
+
+            mUserInfoHelper.addListener(mUserChangedListener);
+            mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+
+            // initialize enabled state
+            onUserStarted(UserHandle.USER_ALL);
+        }
+    }
+
+    public void stopManager() {
+        synchronized (mLock) {
+            mUserInfoHelper.removeListener(mUserChangedListener);
+            mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+
+            // notify and remove all listeners
+            onUserStopped(UserHandle.USER_ALL);
+            removeRegistrationIf(key -> true);
+            mEnabledListeners.clear();
+
+            mStarted = false;
+        }
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    @Nullable
+    public CallerIdentity getIdentity() {
+        return mProvider.getState().identity;
+    }
+
+    @Nullable
+    public ProviderProperties getProperties() {
+        return mProvider.getState().properties;
+    }
+
+    public boolean hasProvider() {
+        return mProvider.getProvider() != null;
+    }
+
+    public boolean isEnabled(int userId) {
+        if (userId == UserHandle.USER_NULL) {
+            return false;
+        }
+
+        Preconditions.checkArgument(userId >= 0);
+
+        synchronized (mLock) {
+            int index = mEnabled.indexOfKey(userId);
+            if (index < 0) {
+                // this generally shouldn't occur, but might be possible due to race conditions
+                // on when we are notified of new users
+                Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
+                onEnabledChanged(userId);
+                index = mEnabled.indexOfKey(userId);
+            }
+
+            return mEnabled.valueAt(index);
+        }
+    }
+
+    public void addEnabledListener(ProviderEnabledListener listener) {
+        synchronized (mLock) {
+            Preconditions.checkState(mStarted);
+            mEnabledListeners.add(listener);
+        }
+    }
+
+    public void removeEnabledListener(ProviderEnabledListener listener) {
+        synchronized (mLock) {
+            Preconditions.checkState(mStarted);
+            mEnabledListeners.remove(listener);
+        }
+    }
+
+    public void setRealProvider(AbstractLocationProvider provider) {
+        synchronized (mLock) {
+            Preconditions.checkState(mStarted);
+            mProvider.setRealProvider(provider);
+        }
+    }
+
+    public void setMockProvider(@Nullable MockProvider provider) {
+        synchronized (mLock) {
+            Preconditions.checkState(mStarted);
+            mProvider.setMockProvider(provider);
+
+            // when removing a mock provider, also clear any mock last locations and reset the
+            // location fudger. the mock provider could have been used to infer the current
+            // location fudger offsets.
+            if (provider == null) {
+                final int lastLocationSize = mLastLocations.size();
+                for (int i = 0; i < lastLocationSize; i++) {
+                    mLastLocations.valueAt(i).clearMock();
+                }
+
+                mLocationFudger.resetOffsets();
+            }
+        }
+    }
+
+    public void setMockProviderAllowed(boolean enabled) {
+        synchronized (mLock) {
+            if (!mProvider.isMock()) {
+                throw new IllegalArgumentException(mName + " provider is not a test provider");
+            }
+
+            mProvider.setMockProviderAllowed(enabled);
+        }
+    }
+
+    public void setMockProviderLocation(Location location) {
+        synchronized (mLock) {
+            if (!mProvider.isMock()) {
+                throw new IllegalArgumentException(mName + " provider is not a test provider");
+            }
+
+            String locationProvider = location.getProvider();
+            if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
+                // The location has an explicit provider that is different from the mock
+                // provider name. The caller may be trying to fool us via b/33091107.
+                EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+                        mName + "!=" + locationProvider);
+            }
+
+            mProvider.setMockProviderLocation(location);
+        }
+    }
+
+    public List<LocationRequest> getMockProviderRequests() {
+        synchronized (mLock) {
+            if (!mProvider.isMock()) {
+                throw new IllegalArgumentException(mName + " provider is not a test provider");
+            }
+
+            return mProvider.getCurrentRequest().locationRequests;
+        }
+    }
+
+    @Nullable
+    public Location getLastLocation(LocationRequest request, CallerIdentity identity,
+            @PermissionLevel int permissionLevel) {
+        Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+        if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
+                identity.getPackageName())) {
+            return null;
+        }
+        if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
+            return null;
+        }
+        if (!request.isLocationSettingsIgnored() && !isEnabled(identity.getUserId())) {
+            return null;
+        }
+
+        Location location = getLastLocation(identity.getUserId(), permissionLevel,
+                request.isLocationSettingsIgnored());
+
+        // we don't note op here because we don't know what the client intends to do with the
+        // location, the client is responsible for noting if necessary
+
+        if (identity.getPid() == Process.myPid() && location != null) {
+            // if delivering to the same process, make a copy of the location first (since
+            // location is mutable)
+            return new Location(location);
+        } else {
+            return location;
+        }
+    }
+
+    @Nullable
+    private Location getLastLocation(int userId, @PermissionLevel int permissionLevel,
+            boolean ignoreLocationSettings) {
+        synchronized (mLock) {
+            LastLocation lastLocation = mLastLocations.get(userId);
+            if (lastLocation == null) {
+                return null;
+            }
+            return lastLocation.get(permissionLevel, ignoreLocationSettings);
+        }
+    }
+
+    public void injectLastLocation(Location location, int userId) {
+        synchronized (mLock) {
+            if (getLastLocation(userId, PERMISSION_FINE, false) == null) {
+                setLastLocation(location, userId);
+            }
+        }
+    }
+
+    private void setLastLocation(Location location, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+            for (int i = 0; i < runningUserIds.length; i++) {
+                setLastLocation(location, runningUserIds[i]);
+            }
+            return;
+        }
+
+        Preconditions.checkArgument(userId >= 0);
+
+        synchronized (mLock) {
+            LastLocation lastLocation = mLastLocations.get(userId);
+            if (lastLocation == null) {
+                lastLocation = new LastLocation();
+                mLastLocations.put(userId, lastLocation);
+            }
+
+            Location coarseLocation = mLocationFudger.createCoarse(location);
+            if (isEnabled(userId)) {
+                lastLocation.set(location, coarseLocation);
+            }
+            lastLocation.setBypass(location, coarseLocation);
+        }
+    }
+
+    public void getCurrentLocation(LocationRequest request, CallerIdentity identity,
+            int permissionLevel, ICancellationSignal cancellationTransport,
+            ILocationCallback callback) {
+        Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+        if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
+            request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
+        }
+
+        GetCurrentLocationListenerRegistration registration =
+                new GetCurrentLocationListenerRegistration(
+                        request,
+                        identity,
+                        new GetCurrentLocationTransport(callback),
+                        permissionLevel);
+
+        synchronized (mLock) {
+            Location lastLocation = getLastLocation(request, identity, permissionLevel);
+            if (lastLocation != null) {
+                long locationAgeMs = NANOSECONDS.toMillis(
+                        SystemClock.elapsedRealtimeNanos()
+                                - lastLocation.getElapsedRealtimeNanos());
+                if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
+                    registration.deliverLocation(lastLocation);
+                    return;
+                }
+
+                if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())
+                        && locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
+                    registration.deliverLocation(null);
+                    return;
+                }
+            }
+
+            // if last location isn't good enough then we add a location request
+            addRegistration(callback.asBinder(), registration);
+            CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
+                    cancellationTransport);
+            if (cancellationSignal != null) {
+                cancellationSignal.setOnCancelListener(
+                        () -> {
+                            synchronized (mLock) {
+                                removeRegistration(callback.asBinder(), registration);
+                            }
+                        });
+            }
+        }
+    }
+
+    public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
+        mProvider.sendExtraCommand(uid, pid, command, extras);
+    }
+
+    public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+            @PermissionLevel int permissionLevel, ILocationListener listener) {
+        Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+        synchronized (mLock) {
+            addRegistration(
+                    listener.asBinder(),
+                    new LocationListenerRegistration(
+                            request,
+                            identity,
+                            new LocationListenerTransport(listener),
+                            permissionLevel));
+        }
+    }
+
+    public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+            @PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
+        Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+        synchronized (mLock) {
+            addRegistration(
+                    pendingIntent,
+                    new LocationPendingIntentRegistration(
+                            request,
+                            identity,
+                            new LocationPendingIntentTransport(mContext, pendingIntent),
+                            permissionLevel));
+        }
+    }
+
+    public void unregisterLocationRequest(ILocationListener listener) {
+        synchronized (mLock) {
+            removeRegistration(listener.asBinder());
+        }
+    }
+
+    public void unregisterLocationRequest(PendingIntent pendingIntent) {
+        synchronized (mLock) {
+            removeRegistration(pendingIntent);
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected void onRegister() {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
+                mBackgroundThrottleIntervalChangedListener);
+        mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
+                mBackgroundThrottlePackageWhitelistChangedListener);
+        mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
+                mLocationPackageBlacklistChangedListener);
+        mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
+                mIgnoreSettingsPackageWhitelistChangedListener);
+        mLocationPermissionsHelper.addListener(mLocationPermissionsListener);
+        mAppForegroundHelper.addListener(mAppForegroundChangedListener);
+        mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener);
+        mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener);
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected void onUnregister() {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        mSettingsHelper.removeOnBackgroundThrottleIntervalChangedListener(
+                mBackgroundThrottleIntervalChangedListener);
+        mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
+                mBackgroundThrottlePackageWhitelistChangedListener);
+        mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
+                mLocationPackageBlacklistChangedListener);
+        mSettingsHelper.removeOnIgnoreSettingsPackageWhitelistChangedListener(
+                mIgnoreSettingsPackageWhitelistChangedListener);
+        mLocationPermissionsHelper.removeListener(mLocationPermissionsListener);
+        mAppForegroundHelper.removeListener(mAppForegroundChangedListener);
+        mLocationPowerSaveModeHelper.removeListener(mLocationPowerSaveModeChangedListener);
+        mScreenInteractiveHelper.removeListener(mScreenInteractiveChangedListener);
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected void onRegistrationAdded(Object key, Registration registration) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        mLocationUsageLogger.logLocationApiUsage(
+                LocationStatsEnums.USAGE_STARTED,
+                LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
+                registration.getIdentity().getPackageName(),
+                registration.getRequest(),
+                key instanceof PendingIntent,
+                key instanceof IBinder,
+                /* geofence= */ null,
+                registration.isForeground());
+
+        mLocationRequestStatistics.startRequesting(
+                registration.getIdentity().getPackageName(),
+                registration.getIdentity().getAttributionTag(),
+                mName,
+                registration.getRequest().getInterval(),
+                registration.isForeground());
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected void onRegistrationRemoved(Object key, Registration registration) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        mLocationRequestStatistics.stopRequesting(
+                registration.getIdentity().getPackageName(),
+                registration.getIdentity().getAttributionTag(),
+                mName);
+
+        mLocationUsageLogger.logLocationApiUsage(
+                LocationStatsEnums.USAGE_ENDED,
+                LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
+                registration.getIdentity().getPackageName(),
+                registration.getRequest(),
+                key instanceof PendingIntent,
+                key instanceof IBinder,
+                /* geofence= */ null,
+                registration.isForeground());
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected boolean registerWithService(ProviderRequest mergedRequest) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        mProvider.setRequest(mergedRequest);
+        return true;
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected boolean reregisterWithService(ProviderRequest oldRequest,
+            ProviderRequest newRequest) {
+        return registerWithService(newRequest);
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected void unregisterWithService() {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+        mProvider.setRequest(ProviderRequest.EMPTY_REQUEST);
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected boolean isActive(Registration registration) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        CallerIdentity identity = registration.getIdentity();
+
+        if (!registration.isPermitted()) {
+            return false;
+        }
+
+        if (!registration.getRequest().isLocationSettingsIgnored()) {
+            if (!isEnabled(identity.getUserId())) {
+                return false;
+            }
+
+            switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
+                case LOCATION_MODE_FOREGROUND_ONLY:
+                    if (!registration.isForeground()) {
+                        return false;
+                    }
+                    break;
+                case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+                    if (!GPS_PROVIDER.equals(mName)) {
+                        break;
+                    }
+                    // fall through
+                case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
+                    // fall through
+                case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
+                    if (!mScreenInteractiveHelper.isInteractive()) {
+                        return false;
+                    }
+                    break;
+                case LOCATION_MODE_NO_CHANGE:
+                    // fall through
+                default:
+                    break;
+            }
+        }
+
+        return !mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
+                identity.getPackageName());
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    protected ProviderRequest mergeRequests(Collection<Registration> registrations) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        ProviderRequest.Builder providerRequest = new ProviderRequest.Builder();
+        // initialize the low power mode to true and set to false if any of the records requires
+        providerRequest.setLowPowerMode(true);
+
+        ArrayList<Registration> providerRegistrations = new ArrayList<>(registrations.size());
+        for (Registration registration : registrations) {
+            LocationRequest locationRequest = registration.getRequest();
+
+            if (locationRequest.isLocationSettingsIgnored()) {
+                providerRequest.setLocationSettingsIgnored(true);
+            }
+            if (!locationRequest.isLowPowerMode()) {
+                providerRequest.setLowPowerMode(false);
+            }
+
+            providerRequest.setInterval(
+                    Math.min(locationRequest.getInterval(), providerRequest.getInterval()));
+            providerRegistrations.add(registration);
+        }
+
+        // collect contributing location requests
+        ArrayList<LocationRequest> providerRequests = new ArrayList<>(providerRegistrations.size());
+        final int registrationsSize = providerRegistrations.size();
+        for (int i = 0; i < registrationsSize; i++) {
+            providerRequests.add(providerRegistrations.get(i).getRequest());
+        }
+
+        providerRequest.setLocationRequests(providerRequests);
+
+        // calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
+        // interval slightly higher that the minimum interval, and spread the blame across all
+        // contributing registrations under that threshold.
+        long thresholdIntervalMs = (providerRequest.getInterval() + 1000) * 3 / 2;
+        if (thresholdIntervalMs < 0) {
+            // handle overflow
+            thresholdIntervalMs = Long.MAX_VALUE;
+        }
+        for (int i = 0; i < registrationsSize; i++) {
+            LocationRequest request = providerRegistrations.get(i).getRequest();
+            if (request.getInterval() <= thresholdIntervalMs) {
+                providerRequest.getWorkSource().add(providerRegistrations.get(i).getWorkSource());
+            }
+        }
+
+        return providerRequest.build();
+    }
+
+    private void onUserChanged(int userId, int change) {
+        synchronized (mLock) {
+            switch (change) {
+                case UserListener.CURRENT_USER_CHANGED:
+                    onEnabledChanged(userId);
+                    break;
+                case UserListener.USER_STARTED:
+                    onUserStarted(userId);
+                    break;
+                case UserListener.USER_STOPPED:
+                    onUserStopped(userId);
+                    break;
+            }
+        }
+    }
+
+    private void onLocationEnabledChanged(int userId) {
+        synchronized (mLock) {
+            onEnabledChanged(userId);
+        }
+    }
+
+    private void onScreenInteractiveChanged(boolean screenInteractive) {
+        synchronized (mLock) {
+            switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
+                case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+                    if (!GPS_PROVIDER.equals(mName)) {
+                        break;
+                    }
+                    // fall through
+                case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
+                    // fall through
+                case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
+                    updateService();
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    private void onBackgroundThrottlePackageWhitelistChanged() {
+        synchronized (mLock) {
+            updateRegistrations(Registration::onProviderLocationRequestChanged);
+        }
+    }
+
+    private void onBackgroundThrottleIntervalChanged() {
+        synchronized (mLock) {
+            updateRegistrations(Registration::onProviderLocationRequestChanged);
+        }
+    }
+
+    private void onLocationPowerSaveModeChanged(@LocationPowerSaveMode int locationPowerSaveMode) {
+        synchronized (mLock) {
+            // this is rare, just assume everything has changed to keep it simple
+            updateRegistrations(registration -> true);
+        }
+    }
+
+    private void onAppForegroundChanged(int uid, boolean foreground) {
+        synchronized (mLock) {
+            updateRegistrations(registration -> registration.onForegroundChanged(uid, foreground));
+        }
+    }
+
+    private void onIgnoreSettingsWhitelistChanged() {
+        synchronized (mLock) {
+            updateRegistrations(Registration::onProviderLocationRequestChanged);
+        }
+    }
+
+    private void onLocationPackageBlacklistChanged(int userId) {
+        synchronized (mLock) {
+            updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
+        }
+    }
+
+    private void onLocationPermissionsChanged(String packageName) {
+        synchronized (mLock) {
+            updateRegistrations(
+                    registration -> registration.onLocationPermissionsChanged(packageName));
+        }
+    }
+
+    private void onLocationPermissionsChanged(int uid) {
+        synchronized (mLock) {
+            updateRegistrations(registration -> registration.onLocationPermissionsChanged(uid));
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    public void onStateChanged(
+            AbstractLocationProvider.State oldState, AbstractLocationProvider.State newState) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        if (oldState.allowed != newState.allowed) {
+            onEnabledChanged(UserHandle.USER_ALL);
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    public void onReportLocation(Location location) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        // don't validate mock locations
+        if (!location.isFromMockProvider()) {
+            if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+                Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
+                return;
+            }
+        }
+
+        if (!location.isComplete()) {
+            Log.w(TAG, "blocking incomplete location from " + mName + " provider");
+            return;
+        }
+
+        // update last location
+        setLastLocation(location, UserHandle.USER_ALL);
+
+        // notify passive provider
+        if (mPassiveManager != null) {
+            mPassiveManager.updateLocation(location);
+        }
+
+        // attempt listener delivery
+        deliverToListeners(registration -> {
+            return registration.acceptLocationChange(location);
+        });
+    }
+
+    @GuardedBy("mLock")
+    @Override
+    public void onReportLocation(List<Location> locations) {
+        if (!GPS_PROVIDER.equals(mName)) {
+            return;
+        }
+
+        mLocationManagerInternal.reportGnssBatchLocations(locations);
+    }
+
+    @GuardedBy("mLock")
+    private void onUserStarted(int userId) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        if (userId == UserHandle.USER_NULL) {
+            return;
+        }
+
+        if (userId == UserHandle.USER_ALL) {
+            // clear the user's prior enabled state to prevent broadcast of enabled state change
+            mEnabled.clear();
+            onEnabledChanged(UserHandle.USER_ALL);
+        } else {
+            Preconditions.checkArgument(userId >= 0);
+
+            // clear the user's prior enabled state to prevent broadcast of enabled state change
+            mEnabled.delete(userId);
+            onEnabledChanged(userId);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onUserStopped(int userId) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        if (userId == UserHandle.USER_NULL) {
+            return;
+        }
+
+        if (userId == UserHandle.USER_ALL) {
+            onEnabledChanged(UserHandle.USER_ALL);
+            mEnabled.clear();
+            mLastLocations.clear();
+        } else {
+            Preconditions.checkArgument(userId >= 0);
+
+            onEnabledChanged(userId);
+            mEnabled.delete(userId);
+            mLastLocations.remove(userId);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onEnabledChanged(int userId) {
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkState(Thread.holdsLock(mLock));
+        }
+
+        if (userId == UserHandle.USER_NULL) {
+            // used during initialization - ignore since many lower level operations (checking
+            // settings for instance) do not support the null user
+            return;
+        } else if (userId == UserHandle.USER_ALL) {
+            final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+            for (int i = 0; i < runningUserIds.length; i++) {
+                onEnabledChanged(runningUserIds[i]);
+            }
+            return;
+        }
+
+        Preconditions.checkArgument(userId >= 0);
+
+        boolean enabled = mStarted
+                && mProvider.getState().allowed
+                && mUserInfoHelper.isCurrentUserId(userId)
+                && mSettingsHelper.isLocationEnabled(userId);
+
+        int index = mEnabled.indexOfKey(userId);
+        Boolean wasEnabled = index < 0 ? null : mEnabled.valueAt(index);
+        if (wasEnabled != null && wasEnabled == enabled) {
+            return;
+        }
+
+        mEnabled.put(userId, enabled);
+
+        if (D) {
+            Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
+        }
+
+        // clear last locations if we become disabled
+        if (!enabled) {
+            LastLocation lastLocation = mLastLocations.get(userId);
+            if (lastLocation != null) {
+                lastLocation.clearLocations();
+            }
+        }
+
+        // do not send change notifications if we just saw this user for the first time
+        if (wasEnabled != null) {
+            // fused and passive provider never get public updates for legacy reasons
+            if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
+                Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
+                        .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
+                        .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, enabled)
+                        .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+            }
+
+            // send updates to internal listeners - since we expect listener changes to be more
+            // frequent than enabled changes, we use copy-on-read instead of copy-on-write
+            if (!mEnabledListeners.isEmpty()) {
+                ProviderEnabledListener[] listeners = mEnabledListeners.toArray(
+                        new ProviderEnabledListener[0]);
+                FgThread.getHandler().post(() -> {
+                    for (int i = 0; i < listeners.length; i++) {
+                        listeners[i].onProviderEnabledChanged(mName, userId, enabled);
+                    }
+                });
+            }
+        }
+
+        // update active state of affected registrations
+        updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
+    }
+
+    public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+        synchronized (mLock) {
+            ipw.print(mName + " provider");
+            if (mProvider.isMock()) {
+                ipw.print(" [mock]");
+            }
+            ipw.println(":");
+            ipw.increaseIndent();
+
+            super.dump(fd, ipw, args);
+
+            int[] userIds = mUserInfoHelper.getRunningUserIds();
+            for (int userId : userIds) {
+                if (userIds.length != 1) {
+                    ipw.println("user " + userId + ":");
+                    ipw.increaseIndent();
+                }
+                ipw.println("last location=" + getLastLocation(userId, PERMISSION_FINE, false));
+                ipw.println("enabled=" + isEnabled(userId));
+                if (userIds.length != 1) {
+                    ipw.decreaseIndent();
+                }
+            }
+        }
+
+        mProvider.dump(fd, ipw, args);
+
+        ipw.decreaseIndent();
+    }
+
+    private static class LastLocation {
+
+        @Nullable private Location mFineLocation;
+        @Nullable private Location mCoarseLocation;
+        @Nullable private Location mFineBypassLocation;
+        @Nullable private Location mCoarseBypassLocation;
+
+        public void clearMock() {
+            if (mFineLocation != null && mFineLocation.isFromMockProvider()) {
+                mFineLocation = null;
+                mCoarseLocation = null;
+            }
+            if (mFineBypassLocation != null && mFineBypassLocation.isFromMockProvider()) {
+                mFineBypassLocation = null;
+                mCoarseBypassLocation = null;
+            }
+        }
+
+        public void clearLocations() {
+            mFineLocation = null;
+            mCoarseLocation = null;
+        }
+
+        @Nullable
+        public Location get(@PermissionLevel int permissionLevel, boolean ignoreLocationSettings) {
+            switch (permissionLevel) {
+                case PERMISSION_FINE:
+                    if (ignoreLocationSettings) {
+                        return mFineBypassLocation;
+                    } else {
+                        return mFineLocation;
+                    }
+                case PERMISSION_COARSE:
+                    if (ignoreLocationSettings) {
+                        return mCoarseBypassLocation;
+                    } else {
+                        return mCoarseLocation;
+                    }
+                default:
+                    // shouldn't be possible to have a client added without location permissions
+                    throw new AssertionError();
+            }
+        }
+
+        public void set(Location location, Location coarseLocation) {
+            mFineLocation = location;
+            mCoarseLocation = calculateNextCoarse(mCoarseLocation, coarseLocation);
+        }
+
+        public void setBypass(Location location, Location coarseLocation) {
+            mFineBypassLocation = location;
+            mCoarseBypassLocation = calculateNextCoarse(mCoarseBypassLocation, coarseLocation);
+        }
+
+        private Location calculateNextCoarse(@Nullable Location oldCoarse, Location newCoarse) {
+            if (oldCoarse == null) {
+                return newCoarse;
+            }
+            // update last coarse interval only if enough time has passed
+            long timeDeltaMs = NANOSECONDS.toMillis(newCoarse.getElapsedRealtimeNanos())
+                        - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
+            if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
+                return newCoarse;
+            } else {
+                return oldCoarse;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index c5bd5e6..fc88f14 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -40,9 +40,8 @@
 
     public MockProvider(ProviderProperties properties, CallerIdentity identity) {
         // using a direct executor is ok because this class has no locks that could deadlock
-        super(DIRECT_EXECUTOR);
+        super(DIRECT_EXECUTOR, identity);
         setProperties(properties);
-        setIdentity(identity);
     }
 
     /** Sets the allowed state of this mock provider. */
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index 54af1c8..d8d435a 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -241,7 +241,6 @@
             if (getState().properties != null) {
                 pw.println("properties=" + getState().properties);
             }
-            pw.println("request=" + mRequest);
         }
 
         if (provider != null) {
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
new file mode 100644
index 0000000..d4999ab
--- /dev/null
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Binder;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.location.util.Injector;
+
+class PassiveLocationProviderManager extends LocationProviderManager {
+
+    PassiveLocationProviderManager(Context context, Injector injector) {
+        super(context, injector, LocationManager.PASSIVE_PROVIDER, null);
+    }
+
+    @Override
+    public void setRealProvider(AbstractLocationProvider provider) {
+        Preconditions.checkArgument(provider instanceof PassiveProvider);
+        super.setRealProvider(provider);
+    }
+
+    @Override
+    public void setMockProvider(@Nullable MockProvider provider) {
+        if (provider != null) {
+            throw new IllegalArgumentException("Cannot mock the passive provider");
+        }
+    }
+
+    public void updateLocation(Location location) {
+        synchronized (mLock) {
+            PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
+            Preconditions.checkState(passiveProvider != null);
+
+            long identity = Binder.clearCallingIdentity();
+            try {
+                passiveProvider.updateLocation(location);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 0b7968b..1b599b0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -16,17 +16,21 @@
 
 package com.android.server.location.gnss;
 
+import static android.location.LocationManager.GPS_PROVIDER;
+
 import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
 import static com.android.server.location.gnss.GnssManagerService.TAG;
 
 import android.annotation.Nullable;
 import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
 import android.location.util.identity.CallerIdentity;
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Process;
 import android.util.ArraySet;
 
+import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.location.listeners.BinderListenerRegistration;
 import com.android.server.location.listeners.ListenerMultiplexer;
@@ -161,8 +165,8 @@
     protected final LocationManagerInternal mLocationManagerInternal;
 
     private final UserListener mUserChangedListener = this::onUserChanged;
-    private final SettingsHelper.UserSettingChangedListener mLocationEnabledChangedListener =
-            this::onLocationEnabledChanged;
+    private final ProviderEnabledListener mProviderEnabledChangedListener =
+            this::onProviderEnabledChanged;
     private final SettingsHelper.GlobalSettingChangedListener
             mBackgroundThrottlePackageWhitelistChangedListener =
             this::onBackgroundThrottlePackageWhitelistChanged;
@@ -233,12 +237,11 @@
         }
 
         CallerIdentity identity = registration.getIdentity();
-        // TODO: this should be checking if the gps provider is enabled, not if location is enabled,
-        //  but this is the same for now.
         return registration.isPermitted()
                 && (registration.isForeground() || isBackgroundRestrictionExempt(identity))
                 && mUserInfoHelper.isCurrentUserId(identity.getUserId())
-                && mSettingsHelper.isLocationEnabled(identity.getUserId())
+                && mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER,
+                identity.getUserId())
                 && !mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
                 identity.getPackageName());
     }
@@ -263,7 +266,8 @@
         }
 
         mUserInfoHelper.addListener(mUserChangedListener);
-        mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+        mLocationManagerInternal.addProviderEnabledListener(GPS_PROVIDER,
+                mProviderEnabledChangedListener);
         mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
                 mBackgroundThrottlePackageWhitelistChangedListener);
         mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
@@ -279,7 +283,8 @@
         }
 
         mUserInfoHelper.removeListener(mUserChangedListener);
-        mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+        mLocationManagerInternal.removeProviderEnabledListener(GPS_PROVIDER,
+                mProviderEnabledChangedListener);
         mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
                 mBackgroundThrottlePackageWhitelistChangedListener);
         mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
@@ -294,7 +299,8 @@
         }
     }
 
-    private void onLocationEnabledChanged(int userId) {
+    private void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+        Preconditions.checkState(GPS_PROVIDER.equals(provider));
         updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
     }
 
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 528cf8a..f94de9b 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -104,18 +104,18 @@
      * should return true if a matching call to {@link #unregisterWithService()} is required to
      * unregister (ie, if registration succeeds).
      *
-     * @see #reregisterWithService(Object)
+     * @see #reregisterWithService(Object, Object)
      */
-    protected abstract boolean registerWithService(TMergedRequest mergedRequest);
+    protected abstract boolean registerWithService(TMergedRequest newRequest);
 
     /**
      * Invoked when the service already has a request, and it is being replaced with a new request.
      * The default implementation unregisters first, then registers with the new merged request, but
      * this may be overridden by subclasses in order to reregister more efficiently.
      */
-    protected boolean reregisterWithService(TMergedRequest mergedRequest) {
+    protected boolean reregisterWithService(TMergedRequest oldRequest, TMergedRequest newRequest) {
         unregisterWithService();
-        return registerWithService(mergedRequest);
+        return registerWithService(newRequest);
     }
 
     /**
@@ -368,6 +368,7 @@
                     mCurrentRequest = null;
                     if (mServiceRegistered) {
                         mServiceRegistered = false;
+                        mCurrentRequest = null;
                         unregisterWithService();
                     }
                     return;
@@ -376,11 +377,15 @@
                 TMergedRequest merged = mergeRequests(actives);
                 if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
                     if (mServiceRegistered) {
-                        mServiceRegistered = reregisterWithService(merged);
+                        mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
                     } else {
                         mServiceRegistered = registerWithService(merged);
                     }
-                    mCurrentRequest = merged;
+                    if (mServiceRegistered) {
+                        mCurrentRequest = merged;
+                    } else {
+                        mCurrentRequest = null;
+                    }
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -389,29 +394,6 @@
     }
 
     /**
-     * Evaluates the given predicate for all registrations, and forces an {@link #updateService()}
-     * if any predicate returns true for an active registration. The predicate will always be
-     * evaluated for all registrations, even inactive registrations, or if it has already returned
-     * true for a prior registration.
-     */
-    protected final void updateService(Predicate<TRegistration> predicate) {
-        synchronized (mRegistrations) {
-            boolean updateService = false;
-            final int size = mRegistrations.size();
-            for (int i = 0; i < size; i++) {
-                TRegistration registration = mRegistrations.valueAt(i);
-                if (predicate.test(registration) && registration.isActive()) {
-                    updateService = true;
-                }
-            }
-
-            if (updateService) {
-                updateService();
-            }
-        }
-    }
-
-    /**
      * Begins buffering calls to {@link #updateService()} until {@link UpdateServiceLock#close()}
      * is called. This is useful to prevent extra work when combining multiple calls (for example,
      * buffering {@code updateService()} until after multiple adds/removes/updates occur.
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index 0bdd131..ac56c51 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -24,6 +24,7 @@
 import android.location.util.identity.CallerIdentity;
 import android.os.Process;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.listeners.ListenerExecutor;
 import com.android.server.FgThread;
 
@@ -39,6 +40,9 @@
  */
 public class ListenerRegistration<TRequest, TListener> implements ListenerExecutor {
 
+    @VisibleForTesting
+    public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
+
     private final Executor mExecutor;
     private final @Nullable TRequest mRequest;
     private final CallerIdentity mIdentity;
@@ -55,9 +59,9 @@
             // there's a slight loophole here for pending intents - pending intent callbacks can
             // always be run on the direct executor since they're always asynchronous, but honestly
             // you shouldn't be using pending intent callbacks within the same process anyways
-            mExecutor =  FgThread.getExecutor();
+            mExecutor = IN_PROCESS_EXECUTOR;
         } else {
-            mExecutor =  DIRECT_EXECUTOR;
+            mExecutor = DIRECT_EXECUTOR;
         }
 
         mRequest = request;
@@ -73,7 +77,7 @@
     /**
      * Returns the request associated with this listener, or null if one wasn't supplied.
      */
-    public final @Nullable TRequest getRequest() {
+    public @Nullable TRequest getRequest() {
         return mRequest;
     }
 
@@ -107,7 +111,7 @@
      */
     protected void onInactive() {}
 
-    final boolean isActive() {
+    public final boolean isActive() {
         return mActive;
     }
 
@@ -120,7 +124,7 @@
         return false;
     }
 
-    final boolean isRegistered() {
+    public final boolean isRegistered() {
         return mListener != null;
     }
 
diff --git a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
index 6a815ea..0698cca 100644
--- a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
@@ -39,7 +39,7 @@
     protected RemovableListenerRegistration(String tag, @Nullable TRequest request,
             CallerIdentity callerIdentity, TListener listener) {
         super(request, callerIdentity, listener);
-        mTag = tag;
+        mTag = Objects.requireNonNull(tag);
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index e568848..f1b89c7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -123,6 +123,7 @@
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
@@ -275,18 +276,18 @@
         }
 
         @Override
-        public void onStartUser(int userHandle) {
-            mLockSettingsService.onStartUser(userHandle);
+        public void onUserStarting(@NonNull TargetUser user) {
+            mLockSettingsService.onStartUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
-            mLockSettingsService.onUnlockUser(userHandle);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mLockSettingsService.onUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onCleanupUser(int userHandle) {
-            mLockSettingsService.onCleanupUser(userHandle);
+        public void onUserStopped(@NonNull TargetUser user) {
+            mLockSettingsService.onCleanupUser(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 9f6c18d..e2f70e3 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -25,6 +25,8 @@
 import static com.android.server.media.MediaKeyDispatcher.isSingleTapOverridden;
 import static com.android.server.media.MediaKeyDispatcher.isTripleTapOverridden;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.NotificationManager;
@@ -85,6 +87,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.Watchdog;
 import com.android.server.Watchdog.Monitor;
 
@@ -333,19 +336,21 @@
     }
 
     @Override
-    public void onStartUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
+    public void onUserStarting(@NonNull TargetUser user) {
+        if (DEBUG) Log.d(TAG, "onStartUser: " + user);
         updateUser();
     }
 
     @Override
-    public void onSwitchUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        if (DEBUG) Log.d(TAG, "onSwitchUser: " + to);
         updateUser();
     }
 
     @Override
-    public void onCleanupUser(int userId) {
+    public void onUserStopped(@NonNull TargetUser targetUser) {
+        int userId = targetUser.getUserIdentifier();
+
         if (DEBUG) Log.d(TAG, "onCleanupUser: " + userId);
         synchronized (mLock) {
             FullUserRecord user = getFullUserRecordLocked(userId);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 1a749b3..94776f8 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,6 +17,8 @@
 package com.android.server.media.projection;
 
 import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.IProcessObserver;
@@ -48,6 +50,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.Watchdog;
 
 import java.io.FileDescriptor;
@@ -122,8 +125,8 @@
     }
 
     @Override
-    public void onSwitchUser(int userId) {
-        mMediaRouter.rebindAsUser(userId);
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        mMediaRouter.rebindAsUser(to.getUserIdentifier());
         synchronized (mLock) {
             if (mProjectionGrant != null) {
                 mProjectionGrant.stop();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index eefff2fb..d71c33e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -261,6 +261,7 @@
 import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.UiThread;
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
@@ -322,7 +323,7 @@
     static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
             "debug.notification.interruptiveness", false);
 
-    static final int MAX_PACKAGE_NOTIFICATIONS = 25;
+    static final int MAX_PACKAGE_NOTIFICATIONS = 50;
     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
 
     // message codes
@@ -2351,11 +2352,11 @@
     }
 
     @Override
-    public void onUnlockUser(@NonNull UserInfo userInfo) {
+    public void onUserUnlocking(@NonNull TargetUser user) {
         mHandler.post(() -> {
             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryUnlockUser");
             try {
-                mHistoryManager.onUserUnlocked(userInfo.id);
+                mHistoryManager.onUserUnlocked(user.getUserIdentifier());
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
@@ -2363,11 +2364,11 @@
     }
 
     @Override
-    public void onStopUser(@NonNull UserInfo userInfo) {
+    public void onUserStopping(@NonNull TargetUser user) {
         mHandler.post(() -> {
             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser");
             try {
-                mHistoryManager.onUserStopped(userInfo.id);
+                mHistoryManager.onUserStopped(user.getUserIdentifier());
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index d6b1b27..cb6e960 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -27,6 +27,7 @@
 import android.os.Build.VERSION_CODES;
 import android.os.OverlayablePolicy;
 import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import java.io.IOException;
@@ -53,11 +54,20 @@
     }
 
     private final IdmapDaemon mIdmapDaemon;
-    private final OverlayableInfoCallback mOverlayableCallback;
+    private final PackageManagerHelper mPackageManager;
 
-    IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) {
-        mOverlayableCallback = verifyCallback;
+    /**
+     * Package name of the reference package defined in 'config-signature' tag of
+     * SystemConfig or empty String if tag not defined. This package is vetted on scan by
+     * PackageManagerService that it's a system package and is used to check if overlay matches
+     * its signature in order to fulfill the config_signature policy.
+     */
+    private final String mConfigSignaturePackage;
+
+    IdmapManager(final IdmapDaemon idmapDaemon, final PackageManagerHelper packageManager) {
+        mPackageManager = packageManager;
         mIdmapDaemon = idmapDaemon;
+        mConfigSignaturePackage = packageManager.getConfigSignaturePackage();
     }
 
     /**
@@ -139,7 +149,7 @@
         int fulfilledPolicies = OverlayablePolicy.PUBLIC;
 
         // Overlay matches target signature
-        if (mOverlayableCallback.signaturesMatching(targetPackage.packageName,
+        if (mPackageManager.signaturesMatching(targetPackage.packageName,
                 overlayPackage.packageName, userId)) {
             fulfilledPolicies |= OverlayablePolicy.SIGNATURE;
         }
@@ -149,6 +159,16 @@
             fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
         }
 
+        // If SystemConfig defines 'config-signature' package, given that
+        // this package is vetted by OverlayManagerService that it's a
+        // preinstalled package, check if overlay matches its signature.
+        if (!TextUtils.isEmpty(mConfigSignaturePackage)
+                && mPackageManager.signaturesMatching(mConfigSignaturePackage,
+                                                           overlayPackage.packageName,
+                                                           userId)) {
+            fulfilledPolicies |= OverlayablePolicy.CONFIG_SIGNATURE;
+        }
+
         // Vendor partition (/vendor)
         if (ai.isVendor()) {
             return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION;
@@ -183,12 +203,12 @@
         String targetOverlayableName = overlayPackage.targetOverlayableName;
         if (targetOverlayableName != null) {
             try {
-                OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget(
+                OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget(
                         targetPackage.packageName, targetOverlayableName, userId);
                 if (overlayableInfo != null && overlayableInfo.actor != null) {
                     String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
-                            overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first;
-                    if (mOverlayableCallback.signaturesMatching(actorPackageName,
+                            overlayableInfo.actor, mPackageManager.getNamedActors()).first;
+                    if (mPackageManager.signaturesMatching(actorPackageName,
                             overlayPackage.packageName, userId)) {
                         return true;
                     }
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index 2bc3499..8c03c6c 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -45,7 +45,7 @@
     // By default, the reason is not logged to prevent leaks of why it failed
     private static final boolean DEBUG_REASON = false;
 
-    private final OverlayableInfoCallback mOverlayableCallback;
+    private final PackageManagerHelper mPackageManager;
 
     /**
      * @return nullable actor result with {@link ActorState} failure status
@@ -79,8 +79,8 @@
         return Pair.create(packageName, ActorState.ALLOWED);
     }
 
-    public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) {
-        mOverlayableCallback = overlayableCallback;
+    public OverlayActorEnforcer(@NonNull PackageManagerHelper packageManager) {
+        mPackageManager = packageManager;
     }
 
     void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName,
@@ -110,7 +110,7 @@
                 return ActorState.ALLOWED;
         }
 
-        String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid);
+        String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid);
         if (ArrayUtils.isEmpty(callingPackageNames)) {
             return ActorState.NO_PACKAGES_FOR_UID;
         }
@@ -125,12 +125,12 @@
 
         if (TextUtils.isEmpty(targetOverlayableName)) {
             try {
-                if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) {
+                if (mPackageManager.doesTargetDefineOverlayable(targetPackageName, userId)) {
                     return ActorState.MISSING_TARGET_OVERLAYABLE_NAME;
                 } else {
                     // If there's no overlayable defined, fallback to the legacy permission check
                     try {
-                        mOverlayableCallback.enforcePermission(
+                        mPackageManager.enforcePermission(
                                 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
 
                         // If the previous method didn't throw, check passed
@@ -146,7 +146,7 @@
 
         OverlayableInfo targetOverlayable;
         try {
-            targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName,
+            targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName,
                     targetOverlayableName, userId);
         } catch (IOException e) {
             return ActorState.UNABLE_TO_GET_TARGET;
@@ -160,7 +160,7 @@
         if (TextUtils.isEmpty(actor)) {
             // If there's no actor defined, fallback to the legacy permission check
             try {
-                mOverlayableCallback.enforcePermission(
+                mPackageManager.enforcePermission(
                         android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
 
                 // If the previous method didn't throw, check passed
@@ -170,7 +170,7 @@
             }
         }
 
-        Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors();
+        Map<String, Map<String, String>> namedActors = mPackageManager.getNamedActors();
         Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors);
         ActorState actorUriState = actorUriPair.second;
         if (actorUriState != ActorState.ALLOWED) {
@@ -178,7 +178,7 @@
         }
 
         String packageName = actorUriPair.first;
-        PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId);
+        PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, userId);
         if (packageInfo == null) {
             return ActorState.MISSING_APP_INFO;
         }
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3968153..a4debc1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -31,6 +31,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
@@ -68,6 +69,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.pm.UserManagerService;
 
 import libcore.util.EmptyArray;
@@ -303,7 +305,11 @@
     }
 
     @Override
-    public void onSwitchUser(final int newUserId) {
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        onSwitchUser(to.getUserIdentifier());
+    }
+
+    private void onSwitchUser(@UserIdInt int newUserId) {
         try {
             traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId);
             // ensure overlays in the settings are up-to-date, and propagate
@@ -1053,8 +1059,7 @@
         }
     }
 
-    private static final class PackageManagerHelperImpl implements PackageManagerHelper,
-            OverlayableInfoCallback {
+    private static final class PackageManagerHelperImpl implements PackageManagerHelper  {
 
         private final Context mContext;
         private final IPackageManager mPackageManager;
@@ -1127,6 +1132,14 @@
             return overlays;
         }
 
+        @Override
+        public String getConfigSignaturePackage() {
+            final String[] pkgs = mPackageManagerInternal.getKnownPackageNames(
+                    PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE,
+                    UserHandle.USER_SYSTEM);
+            return (pkgs.length == 0) ? null : pkgs[0];
+        }
+
         @Nullable
         @Override
         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
deleted file mode 100644
index 5066ecd..0000000
--- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java
+++ /dev/null
@@ -1,83 +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.om;
-
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.om.OverlayableInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-
-import com.android.server.pm.PackageManagerServiceUtils;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * Delegate to the system for querying information about overlayables and packages.
- */
-public interface OverlayableInfoCallback {
-
-    /**
-     * Read from the APK and AndroidManifest of a package to return the overlayable defined for
-     * a given name.
-     *
-     * @throws IOException if the target can't be read
-     */
-    @Nullable
-    OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
-            @NonNull String targetOverlayableName, int userId)
-            throws IOException;
-
-    /**
-     * @see PackageManager#getPackagesForUid(int)
-     */
-    @Nullable
-    String[] getPackagesForUid(int uid);
-
-    /**
-     * @param userId user to filter package visibility by
-     * @see PackageManager#getPackageInfo(String, int)
-     */
-    @Nullable
-    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
-
-    /**
-     * @return map of system pre-defined, uniquely named actors; keys are namespace,
-     * value maps actor name to package name
-     */
-    @NonNull
-    Map<String, Map<String, String>> getNamedActors();
-
-    /**
-     * @return true if the target package has declared an overlayable
-     */
-    boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException;
-
-    /**
-     * @throws SecurityException containing message if the caller doesn't have the given
-     *                           permission
-     */
-    void enforcePermission(String permission, String message) throws SecurityException;
-
-    /**
-     * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages
-     *     in the system returns {@link PackageManager#SIGNATURE_MATCH}
-     */
-    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
-}
diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java
index ec9c5e6..b1a8b4e 100644
--- a/services/core/java/com/android/server/om/PackageManagerHelper.java
+++ b/services/core/java/com/android/server/om/PackageManagerHelper.java
@@ -17,11 +17,17 @@
 package com.android.server.om;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.OverlayableInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality,
@@ -30,7 +36,65 @@
  * @hide
  */
 interface PackageManagerHelper {
-    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
-    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+    /**
+     * @return true if the target package has declared an overlayable
+     */
+    boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException;
+
+    /**
+     * @throws SecurityException containing message if the caller doesn't have the given
+     *                           permission
+     */
+    void enforcePermission(String permission, String message) throws SecurityException;
+
+    /**
+     * Returns the package name of the reference package defined in 'overlay-config-signature' tag
+     * of SystemConfig. This package is vetted on scan by PackageManagerService that it's a system
+     * package and is used to check if overlay matches its signature in order to fulfill the
+     * config_signature policy.
+     */
+    @Nullable
+    String getConfigSignaturePackage();
+
+    /**
+     * @return map of system pre-defined, uniquely named actors; keys are namespace,
+     * value maps actor name to package name
+     */
+    @NonNull
+    Map<String, Map<String, String>> getNamedActors();
+
+    /**
+     * @see PackageManagerInternal#getOverlayPackages(int)
+     */
     List<PackageInfo> getOverlayPackages(int userId);
+
+    /**
+     * Read from the APK and AndroidManifest of a package to return the overlayable defined for
+     * a given name.
+     *
+     * @throws IOException if the target can't be read
+     */
+    @Nullable
+    OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
+            @NonNull String targetOverlayableName, int userId)
+            throws IOException;
+
+    /**
+     * @see PackageManager#getPackagesForUid(int)
+     */
+    @Nullable
+    String[] getPackagesForUid(int uid);
+
+    /**
+     * @param userId user to filter package visibility by
+     * @see PackageManager#getPackageInfo(String, int)
+     */
+    @Nullable
+    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
+
+    /**
+     * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages
+     *     in the system returns {@link PackageManager#SIGNATURE_MATCH}
+     */
+    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
 }
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 249b6801..07527c2 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -270,11 +270,12 @@
     abstract boolean revertActiveSessions();
 
     /**
-     * Abandons the staged session with the given sessionId.
+     * Abandons the staged session with the given sessionId. Client should handle {@code false}
+     * return value carefully as failure here can leave device in inconsistent state.
      *
-     * @return {@code true} upon success, {@code false} if any remote exception occurs
+     * @return {@code true} upon success, {@code false} if any exception occurs
      */
-    abstract boolean abortStagedSession(int sessionId) throws PackageManagerException;
+    abstract boolean abortStagedSession(int sessionId);
 
     /**
      * Uninstalls given {@code apexPackage}.
@@ -753,17 +754,13 @@
         }
 
         @Override
-        boolean abortStagedSession(int sessionId) throws PackageManagerException {
+        boolean abortStagedSession(int sessionId) {
             try {
                 waitForApexService().abortStagedSession(sessionId);
                 return true;
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Unable to contact apexservice", re);
-                return false;
             } catch (Exception e) {
-                throw new PackageManagerException(
-                        PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                        "Failed to abort staged session : " + e.getMessage());
+                Slog.e(TAG, e.getMessage(), e);
+                return false;
             }
         }
 
@@ -1122,7 +1119,7 @@
         }
 
         @Override
-        boolean abortStagedSession(int sessionId) throws PackageManagerException {
+        boolean abortStagedSession(int sessionId) {
             throw new UnsupportedOperationException();
         }
 
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index c3c2e5e..92c0c6a 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -137,11 +137,11 @@
     @VisibleForTesting(visibility = PRIVATE)
     AppsFilter(StateProvider stateProvider,
             FeatureConfig featureConfig,
-            String[] forceQueryableWhitelist,
+            String[] forceQueryableList,
             boolean systemAppsQueryable,
             @Nullable OverlayReferenceMapper.Provider overlayProvider) {
         mFeatureConfig = featureConfig;
-        mForceQueryableByDevicePackageNames = forceQueryableWhitelist;
+        mForceQueryableByDevicePackageNames = forceQueryableList;
         mSystemAppsQueryable = systemAppsQueryable;
         mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
                 overlayProvider);
@@ -746,11 +746,11 @@
      * @param users            the set of users that should be evaluated for this calculation
      * @param existingSettings the set of all package settings that currently exist on device
      * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the
-     * provided setting or null if the app is visible to all and no whitelist should be
+     * provided setting or null if the app is visible to all and no allow list should be
      * applied.
      */
     @Nullable
-    public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users,
+    public SparseArray<int[]> getVisibilityAllowList(PackageSetting setting, int[] users,
             ArrayMap<String, PackageSetting> existingSettings) {
         if (mForceQueryable.contains(setting.appId)) {
             return null;
@@ -761,14 +761,14 @@
             final int userId = users[u];
             int[] appIds = new int[existingSettings.size()];
             int[] buffer = null;
-            int whitelistSize = 0;
+            int allowListSize = 0;
             for (int i = existingSettings.size() - 1; i >= 0; i--) {
                 final PackageSetting existingSetting = existingSettings.valueAt(i);
                 final int existingAppId = existingSetting.appId;
                 if (existingAppId < Process.FIRST_APPLICATION_UID) {
                     continue;
                 }
-                final int loc = Arrays.binarySearch(appIds, 0, whitelistSize, existingAppId);
+                final int loc = Arrays.binarySearch(appIds, 0, allowListSize, existingAppId);
                 if (loc >= 0) {
                     continue;
                 }
@@ -778,13 +778,13 @@
                         buffer = new int[appIds.length];
                     }
                     final int insert = ~loc;
-                    System.arraycopy(appIds, insert, buffer, 0, whitelistSize - insert);
+                    System.arraycopy(appIds, insert, buffer, 0, allowListSize - insert);
                     appIds[insert] = existingAppId;
-                    System.arraycopy(buffer, 0, appIds, insert + 1, whitelistSize - insert);
-                    whitelistSize++;
+                    System.arraycopy(buffer, 0, appIds, insert + 1, allowListSize - insert);
+                    allowListSize++;
                 }
             }
-            result.put(userId, Arrays.copyOf(appIds, whitelistSize));
+            result.put(userId, Arrays.copyOf(appIds, allowListSize));
         }
         return result;
     }
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index fe6aad7..e48862e 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -14,16 +14,16 @@
 per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
 
 # dex
-per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file BackgroundDexOptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file CompilerStats.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file DynamicCodeLoggingService.java = alanstokes@google.com, agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file InstructionSets.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file OtaDexoptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file OtaDexoptShellCommand.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageDexOptimizer.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageUsage.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file AbstractStatsBase.java = calin@google.com, ngeoffray@google.com
+per-file BackgroundDexOptService.java = calin@google.com, ngeoffray@google.com
+per-file CompilerStats.java = calin@google.com, ngeoffray@google.com
+per-file DynamicCodeLoggingService.java = alanstokes@google.com, calin@google.com, ngeoffray@google.com
+per-file InstructionSets.java = calin@google.com, ngeoffray@google.com
+per-file OtaDexoptService.java = calin@google.com, ngeoffray@google.com
+per-file OtaDexoptShellCommand.java = calin@google.com, ngeoffray@google.com
+per-file PackageDexOptimizer.java = calin@google.com, ngeoffray@google.com
+per-file PackageManagerServiceCompilerMapping.java = calin@google.com, ngeoffray@google.com
+per-file PackageUsage.java = calin@google.com, ngeoffray@google.com
 
 # multi user / cross profile
 per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 312dcdd..55e7ca8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1284,10 +1284,16 @@
             int N = mSessions.size();
             for (int i = 0; i < N; i++) {
                 final PackageInstallerSession session = mSessions.valueAt(i);
-                if (session.isStagedAndInTerminalState()) {
+
+                // Do not print finalized staged session as active install sessions
+                final PackageInstallerSession rootSession = session.hasParentSessionId()
+                        ? getSession(session.getParentSessionId())
+                        : session;
+                if (rootSession.isStagedAndInTerminalState()) {
                     finalizedSessions.add(session);
                     continue;
                 }
+
                 session.dump(pw);
                 pw.println();
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index fc94e08..ca8a68b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1764,21 +1764,21 @@
 
     private void verifyNonStaged(List<PackageInstallerSession> childSessions)
             throws PackageManagerException {
-        final PackageManagerService.ActiveInstallSession verifyingSession =
-                makeSessionActiveForVerification();
+        final PackageManagerService.VerificationParams verifyingSession =
+                makeVerificationParams();
         if (verifyingSession == null) {
             return;
         }
         if (isMultiPackage()) {
-            List<PackageManagerService.ActiveInstallSession> verifyingChildSessions =
+            List<PackageManagerService.VerificationParams> verifyingChildSessions =
                     new ArrayList<>(childSessions.size());
             boolean success = true;
             PackageManagerException failure = null;
             for (int i = 0; i < childSessions.size(); ++i) {
                 final PackageInstallerSession session = childSessions.get(i);
                 try {
-                    final PackageManagerService.ActiveInstallSession verifyingChildSession =
-                            session.makeSessionActiveForVerification();
+                    final PackageManagerService.VerificationParams verifyingChildSession =
+                            session.makeVerificationParams();
                     if (verifyingChildSession != null) {
                         verifyingChildSessions.add(verifyingChildSession);
                     }
@@ -1805,21 +1805,21 @@
 
     private void installNonStaged(List<PackageInstallerSession> childSessions)
             throws PackageManagerException {
-        final PackageManagerService.ActiveInstallSession installingSession =
-                makeSessionActiveForInstall();
+        final PackageManagerService.InstallParams installingSession =
+                makeInstallParams();
         if (installingSession == null) {
             return;
         }
         if (isMultiPackage()) {
-            List<PackageManagerService.ActiveInstallSession> installingChildSessions =
+            List<PackageManagerService.InstallParams> installingChildSessions =
                     new ArrayList<>(childSessions.size());
             boolean success = true;
             PackageManagerException failure = null;
             for (int i = 0; i < childSessions.size(); ++i) {
                 final PackageInstallerSession session = childSessions.get(i);
                 try {
-                    final PackageManagerService.ActiveInstallSession installingChildSession =
-                            session.makeSessionActiveForInstall();
+                    final PackageManagerService.InstallParams installingChildSession =
+                            session.makeInstallParams();
                     if (installingChildSession != null) {
                         installingChildSessions.add(installingChildSession);
                     }
@@ -1846,10 +1846,11 @@
 
     /**
      * Stages this session for verification and returns a
-     * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
+     * {@link PackageManagerService.VerificationParams} representing this new staged state or null
      * in case permissions need to be requested before verification can proceed.
      */
-    private PackageManagerService.ActiveInstallSession makeSessionActiveForVerification()
+    @Nullable
+    private PackageManagerService.VerificationParams makeVerificationParams()
             throws PackageManagerException {
         assertNotLocked("makeSessionActive");
 
@@ -1890,12 +1891,12 @@
         }
 
         synchronized (mLock) {
-            return makeSessionActiveForVerificationLocked();
+            return makeVerificationParamsLocked();
         }
     }
 
     @GuardedBy("mLock")
-    private PackageManagerService.ActiveInstallSession makeSessionActiveForVerificationLocked()
+    private PackageManagerService.VerificationParams makeVerificationParamsLocked()
             throws PackageManagerException {
         if (!params.isMultiPackage) {
             Objects.requireNonNull(mPackageName);
@@ -1991,11 +1992,9 @@
         }
 
         mRelinquished = true;
-        // TODO(159331446): create VerificationParams directly by passing information that is
-        //  required for verification only
-        return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
-                localObserver, sessionId, params, mInstallerUid, mInstallSource, user,
-                mSigningDetails);
+
+        return mPm.new VerificationParams(user, stageDir, localObserver, params,
+                mInstallSource, mInstallerUid, mSigningDetails, sessionId);
     }
 
     private void onVerificationComplete() {
@@ -2018,9 +2017,9 @@
 
     /**
      * Stages this session for install and returns a
-     * {@link PackageManagerService.ActiveInstallSession} representing this new staged state.
+     * {@link PackageManagerService.InstallParams} representing this new staged state.
      */
-    private PackageManagerService.ActiveInstallSession makeSessionActiveForInstall()
+    private PackageManagerService.InstallParams makeInstallParams()
             throws PackageManagerException {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2057,9 +2056,8 @@
         }
 
         synchronized (mLock) {
-            return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
-                    localObserver, sessionId, params, mInstallerUid, mInstallSource, user,
-                    mSigningDetails);
+            return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
+                    mSigningDetails, mInstallerUid);
         }
     }
 
@@ -3323,7 +3321,8 @@
     /** {@hide} */
     void setStagedSessionReady() {
         synchronized (mLock) {
-            if (mDestroyed) return; // Do not allow destroyed staged session to change state
+            // Do not allow destroyed/failed staged session to change state
+            if (mDestroyed || mStagedSessionFailed) return;
             mStagedSessionReady = true;
             mStagedSessionApplied = false;
             mStagedSessionFailed = false;
@@ -3334,10 +3333,10 @@
     }
 
     /** {@hide} */
-    void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
-                                String errorMessage) {
+    void setStagedSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage) {
         synchronized (mLock) {
-            if (mDestroyed) return; // Do not allow destroyed staged session to change state
+            // Do not allow destroyed/failed staged session to change state
+            if (mDestroyed || mStagedSessionFailed) return;
             mStagedSessionReady = false;
             mStagedSessionApplied = false;
             mStagedSessionFailed = true;
@@ -3352,7 +3351,8 @@
     /** {@hide} */
     void setStagedSessionApplied() {
         synchronized (mLock) {
-            if (mDestroyed) return; // Do not allow destroyed staged session to change state
+            // Do not allow destroyed/failed staged session to change state
+            if (mDestroyed || mStagedSessionFailed) return;
             mStagedSessionReady = false;
             mStagedSessionApplied = true;
             mStagedSessionFailed = false;
@@ -3402,7 +3402,7 @@
     private void destroyInternal() {
         synchronized (mLock) {
             mSealed = true;
-            if (!params.isStaged || isStagedAndInTerminalState()) {
+            if (!params.isStaged) {
                 mDestroyed = true;
             }
             // Force shut down all bridges
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index aecc8dd..dbdcc4f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -120,6 +120,7 @@
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
 import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
@@ -1128,6 +1129,7 @@
         public @Nullable String storageManagerPackage;
         public @Nullable String defaultTextClassifierPackage;
         public @Nullable String systemTextClassifierPackage;
+        public @Nullable String overlayConfigSignaturePackage;
         public ViewCompiler viewCompiler;
         public @Nullable String wellbeingPackage;
         public @Nullable String retailDemoPackage;
@@ -1660,6 +1662,7 @@
     final @Nullable String mServicesExtensionPackageName;
     final @Nullable String mSharedSystemSharedLibraryPackageName;
     final @Nullable String mRetailDemoPackage;
+    final @Nullable String mOverlayConfigSignaturePackage;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
     private final CompilerStats mCompilerStats = new CompilerStats();
@@ -2213,17 +2216,17 @@
                 }
                 extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
                 // Send to all running apps.
-                final SparseArray<int[]> newBroadcastWhitelist;
+                final SparseArray<int[]> newBroadcastAllowList;
 
                 synchronized (mLock) {
-                    newBroadcastWhitelist = mAppsFilter.getVisibilityWhitelist(
+                    newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
                             getPackageSettingInternal(res.name, Process.SYSTEM_UID),
                             updateUserIds, mSettings.mPackages);
                 }
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                         extras, 0 /*flags*/,
                         null /*targetPackage*/, null /*finishedReceiver*/,
-                        updateUserIds, instantUserIds, newBroadcastWhitelist);
+                        updateUserIds, instantUserIds, newBroadcastAllowList);
                 if (installerPackageName != null) {
                     // Send to the installer, even if it's not running.
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
@@ -2255,7 +2258,7 @@
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                             packageName, extras, 0 /*flags*/,
                             null /*targetPackage*/, null /*finishedReceiver*/,
-                            updateUserIds, instantUserIds, res.removedInfo.broadcastWhitelist);
+                            updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList);
                     if (installerPackageName != null) {
                         sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                                 extras, 0 /*flags*/,
@@ -2817,6 +2820,7 @@
         mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
         mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
         mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
+        mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
 
         mResolveComponentName = testParams.resolveComponentName;
         mPackages.putAll(testParams.packages);
@@ -3382,6 +3386,7 @@
             mAppPredictionServicePackage = getAppPredictionServicePackageName();
             mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
             mRetailDemoPackage = getRetailDemoPackageName();
+            mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
@@ -4208,13 +4213,9 @@
         Iterator<ResolveInfo> iter = matches.iterator();
         while (iter.hasNext()) {
             final ResolveInfo rInfo = iter.next();
-            final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
-            if (ps != null) {
-                final PermissionsState permissionsState = ps.getPermissionsState();
-                if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)
-                        || Build.IS_ENG) {
-                    continue;
-                }
+            if (checkPermission(Manifest.permission.INSTALL_PACKAGES,
+                    rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || Build.IS_ENG) {
+                continue;
             }
             iter.remove();
         }
@@ -8594,10 +8595,9 @@
     private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
             String[] permissions, boolean[] tmp, int flags, int userId) {
         int numMatch = 0;
-        final PermissionsState permissionsState = ps.getPermissionsState();
         for (int i=0; i<permissions.length; i++) {
             final String permission = permissions[i];
-            if (permissionsState.hasPermission(permission, userId)) {
+            if (checkPermission(permission, ps.name, userId) == PERMISSION_GRANTED) {
                 tmp[i] = true;
                 numMatch++;
             } else {
@@ -12122,12 +12122,8 @@
                 if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                     // Exempt SharedUsers signed with the platform key.
                     PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
-                    if ((platformPkgSetting.signatures.mSigningDetails
-                            != PackageParser.SigningDetails.UNKNOWN)
-                            && (compareSignatures(
-                                    platformPkgSetting.signatures.mSigningDetails.signatures,
-                            pkg.getSigningDetails().signatures)
-                                            != PackageManager.SIGNATURE_MATCH)) {
+                    if (!comparePackageSignatures(platformPkgSetting,
+                            pkg.getSigningDetails().signatures)) {
                         throw new PackageManagerException("Apps that share a user with a " +
                                 "privileged app must themselves be marked as privileged. " +
                                 pkg.getPackageName() + " shares privileged user " +
@@ -12174,12 +12170,8 @@
                     if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) {
                         final PackageSetting platformPkgSetting =
                                 mSettings.getPackageLPr("android");
-                        if ((platformPkgSetting.signatures.mSigningDetails
-                                    != PackageParser.SigningDetails.UNKNOWN)
-                                && (compareSignatures(
-                                        platformPkgSetting.signatures.mSigningDetails.signatures,
-                                pkg.getSigningDetails().signatures)
-                                    != PackageManager.SIGNATURE_MATCH)) {
+                        if (!comparePackageSignatures(platformPkgSetting,
+                                pkg.getSigningDetails().signatures)) {
                             throw new PackageManagerException("Overlay "
                                     + pkg.getPackageName()
                                     + " must target Q or later, "
@@ -12188,24 +12180,35 @@
                     }
 
                     // A non-preloaded overlay package, without <overlay android:targetName>, will
-                    // only be used if it is signed with the same certificate as its target. If the
-                    // target is already installed, check this here to augment the last line of
-                    // defence which is OMS.
+                    // only be used if it is signed with the same certificate as its target OR if
+                    // it is signed with the same certificate as a reference package declared
+                    // in 'config-signature' tag of SystemConfig.
+                    // If the target is already installed or 'config-signature' tag in SystemConfig
+                    // is set, check this here to augment the last line of defence which is OMS.
                     if (pkg.getOverlayTargetName() == null) {
                         final PackageSetting targetPkgSetting =
                                 mSettings.getPackageLPr(pkg.getOverlayTarget());
                         if (targetPkgSetting != null) {
-                            if ((targetPkgSetting.signatures.mSigningDetails
-                                        != PackageParser.SigningDetails.UNKNOWN)
-                                    && (compareSignatures(
-                                            targetPkgSetting.signatures.mSigningDetails.signatures,
-                                    pkg.getSigningDetails().signatures)
-                                        != PackageManager.SIGNATURE_MATCH)) {
-                                throw new PackageManagerException("Overlay "
-                                        + pkg.getPackageName() + " and target "
-                                        + pkg.getOverlayTarget() + " signed with"
-                                        + " different certificates, and the overlay lacks"
-                                        + " <overlay android:targetName>");
+                            if (!comparePackageSignatures(targetPkgSetting,
+                                    pkg.getSigningDetails().signatures)) {
+                                // check reference signature
+                                if (mOverlayConfigSignaturePackage == null) {
+                                    throw new PackageManagerException("Overlay "
+                                            + pkg.getPackageName() + " and target "
+                                            + pkg.getOverlayTarget() + " signed with"
+                                            + " different certificates, and the overlay lacks"
+                                            + " <overlay android:targetName>");
+                                }
+                                final PackageSetting refPkgSetting =
+                                        mSettings.getPackageLPr(mOverlayConfigSignaturePackage);
+                                if (!comparePackageSignatures(refPkgSetting,
+                                        pkg.getSigningDetails().signatures)) {
+                                    throw new PackageManagerException("Overlay "
+                                            + pkg.getPackageName() + " signed with a different "
+                                            + "certificate than both the reference package and "
+                                            + "target " + pkg.getOverlayTarget() + ", and the "
+                                            + "overlay lacks <overlay android:targetName>");
+                                }
                             }
                         }
                     }
@@ -12675,7 +12678,7 @@
     public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras,
             final int flags, final String targetPkg, final IIntentReceiver finishedReceiver,
             final int[] userIds, int[] instantUserIds,
-            @Nullable SparseArray<int[]> broadcastWhitelist) {
+            @Nullable SparseArray<int[]> broadcastAllowList) {
         mHandler.post(() -> {
             try {
                 final IActivityManager am = ActivityManager.getService();
@@ -12687,7 +12690,7 @@
                     resolvedUserIds = userIds;
                 }
                 doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
-                        resolvedUserIds, false, broadcastWhitelist);
+                        resolvedUserIds, false, broadcastAllowList);
                 if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
                     doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
                             instantUserIds, true, null);
@@ -12760,7 +12763,7 @@
      */
     private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras,
             int flags, String targetPkg, IIntentReceiver finishedReceiver,
-            int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastWhitelist) {
+            int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList) {
         for (int id : userIds) {
             final Intent intent = new Intent(action,
                     pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
@@ -12790,7 +12793,7 @@
             mInjector.getActivityManagerInternal().broadcastIntent(
                     intent, finishedReceiver, requiredPermissions,
                     finishedReceiver != null, id,
-                    broadcastWhitelist == null ? null : broadcastWhitelist.get(id));
+                    broadcastAllowList == null ? null : broadcastAllowList.get(id));
         }
     }
 
@@ -12853,15 +12856,8 @@
         return installReason;
     }
 
-    void installStage(ActiveInstallSession activeInstallSession) {
-        if (DEBUG_INSTANT) {
-            if ((activeInstallSession.getSessionParams().installFlags
-                    & PackageManager.INSTALL_INSTANT_APP) != 0) {
-                Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
-            }
-        }
+    void installStage(InstallParams params) {
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        final InstallParams params = new InstallParams(activeInstallSession);
         params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -12873,11 +12869,11 @@
         mHandler.sendMessage(msg);
     }
 
-    void installStage(ActiveInstallSession parent, List<ActiveInstallSession> children)
+    void installStage(InstallParams parent, List<InstallParams> children)
             throws PackageManagerException {
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final MultiPackageInstallParams params =
-                new MultiPackageInstallParams(UserHandle.ALL, parent, children);
+                new MultiPackageInstallParams(parent, children);
         params.setTraceMethod("installStageMultiPackage")
                 .setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
@@ -12889,17 +12885,16 @@
         mHandler.sendMessage(msg);
     }
 
-    void verifyStage(ActiveInstallSession activeInstallSession) {
-        final VerificationParams params = new VerificationParams(activeInstallSession);
+    void verifyStage(VerificationParams params) {
         mHandler.post(()-> {
             params.startCopy();
         });
     }
 
-    void verifyStage(ActiveInstallSession parent, List<ActiveInstallSession> children)
+    void verifyStage(VerificationParams parent, List<VerificationParams> children)
             throws PackageManagerException {
         final MultiPackageVerificationParams params =
-                new MultiPackageVerificationParams(UserHandle.ALL, parent, children);
+                new MultiPackageVerificationParams(parent, children);
         mHandler.post(()-> {
             params.startCopy();
         });
@@ -12938,7 +12933,7 @@
 
         sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                 packageName, extras, 0, null, null, userIds, instantUserIds,
-                mAppsFilter.getVisibilityWhitelist(
+                mAppsFilter.getVisibilityAllowList(
                         getPackageSettingInternal(packageName, Process.SYSTEM_UID),
                         userIds, mSettings.mPackages));
         if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
@@ -14765,23 +14760,19 @@
      * committed together.
      */
     class MultiPackageInstallParams extends HandlerParams {
-        private final ArrayList<InstallParams> mChildParams;
+        private final List<InstallParams> mChildParams;
         private final Map<InstallArgs, Integer> mCurrentState;
 
-        MultiPackageInstallParams(
-                @NonNull UserHandle user,
-                @NonNull ActiveInstallSession parent,
-                @NonNull List<ActiveInstallSession> activeInstallSessions)
+        MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
                 throws PackageManagerException {
-            super(user);
-            if (activeInstallSessions.size() == 0) {
+            super(parent.getUser());
+            if (childParams.size() == 0) {
                 throw new PackageManagerException("No child sessions found!");
             }
-            mChildParams = new ArrayList<>(activeInstallSessions.size());
-            for (int i = 0; i < activeInstallSessions.size(); i++) {
-                final InstallParams childParams = new InstallParams(activeInstallSessions.get(i));
-                childParams.mParentInstallParams = this;
-                this.mChildParams.add(childParams);
+            mChildParams = childParams;
+            for (int i = 0; i < childParams.size(); i++) {
+                final InstallParams childParam = childParams.get(i);
+                childParam.mParentInstallParams = this;
             }
             this.mCurrentState = new ArrayMap<>(mChildParams.size());
         }
@@ -14826,7 +14817,6 @@
     }
 
     class InstallParams extends HandlerParams {
-        // TODO: see if we can collapse this into ActiveInstallSession
         final OriginInfo origin;
         final MoveInfo move;
         final IPackageInstallObserver2 observer;
@@ -14846,10 +14836,7 @@
 
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, InstallSource installSource, String volumeUuid,
-                UserHandle user, String packageAbiOverride,
-                String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
-                int autoRevokePermissionsMode,
-                SigningDetails signingDetails, int installReason, int dataLoaderType) {
+                UserHandle user, String packageAbiOverride) {
             super(user);
             this.origin = origin;
             this.move = move;
@@ -14858,40 +14845,33 @@
             this.installSource = Preconditions.checkNotNull(installSource);
             this.volumeUuid = volumeUuid;
             this.packageAbiOverride = packageAbiOverride;
-            this.grantedRuntimePermissions = grantedPermissions;
-            this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
-            this.autoRevokePermissionsMode = autoRevokePermissionsMode;
-            this.signingDetails = signingDetails;
-            this.installReason = installReason;
+
+            this.grantedRuntimePermissions = null;
+            this.whitelistedRestrictedPermissions = null;
+            this.autoRevokePermissionsMode = MODE_DEFAULT;
+            this.signingDetails = PackageParser.SigningDetails.UNKNOWN;
+            this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
             this.forceQueryableOverride = false;
-            this.mDataLoaderType = dataLoaderType;
+            this.mDataLoaderType = DataLoaderType.NONE;
         }
 
-        InstallParams(ActiveInstallSession activeInstallSession) {
-            super(activeInstallSession.getUser());
-            final PackageInstaller.SessionParams sessionParams =
-                    activeInstallSession.getSessionParams();
-            if (DEBUG_INSTANT) {
-                if ((sessionParams.installFlags
-                        & PackageManager.INSTALL_INSTANT_APP) != 0) {
-                    Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
-                }
-            }
-            origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
+        InstallParams(File stagedDir, IPackageInstallObserver2 observer,
+                PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+                UserHandle user, SigningDetails signingDetails, int installerUid) {
+            super(user);
+            origin = OriginInfo.fromStagedFile(stagedDir);
             move = null;
             installReason = fixUpInstallReason(
-                    activeInstallSession.getInstallSource().installerPackageName,
-                    activeInstallSession.getInstallerUid(),
-                    sessionParams.installReason);
-            observer = activeInstallSession.getObserver();
+                    installSource.installerPackageName, installerUid, sessionParams.installReason);
+            this.observer = observer;
             installFlags = sessionParams.installFlags;
-            installSource = activeInstallSession.getInstallSource();
+            this.installSource = installSource;
             volumeUuid = sessionParams.volumeUuid;
             packageAbiOverride = sessionParams.abiOverride;
             grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
             whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
             autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
-            signingDetails = activeInstallSession.getSigningDetails();
+            this.signingDetails = signingDetails;
             forceQueryableOverride = sessionParams.forceQueryableOverride;
             mDataLoaderType = (sessionParams.dataLoaderParams != null)
                     ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
@@ -15072,27 +15052,25 @@
      */
     class MultiPackageVerificationParams extends HandlerParams {
         private final IPackageInstallObserver2 mObserver;
-        private final ArrayList<VerificationParams> mChildParams;
+        private final List<VerificationParams> mChildParams;
         private final Map<VerificationParams, Integer> mVerificationState;
 
         MultiPackageVerificationParams(
-                @NonNull UserHandle user,
-                @NonNull ActiveInstallSession parent,
-                @NonNull List<ActiveInstallSession> activeInstallSessions)
+                VerificationParams parent,
+                List<VerificationParams> children)
                 throws PackageManagerException {
-            super(user);
-            if (activeInstallSessions.size() == 0) {
+            super(parent.getUser());
+            if (children.size() == 0) {
                 throw new PackageManagerException("No child sessions found!");
             }
-            mChildParams = new ArrayList<>(activeInstallSessions.size());
-            for (int i = 0; i < activeInstallSessions.size(); i++) {
-                final VerificationParams childParams =
-                        new VerificationParams(activeInstallSessions.get(i));
+            mChildParams = children;
+            // Provide every child with reference to this object as parent
+            for (int i = 0; i < children.size(); i++) {
+                final VerificationParams childParams = children.get(i);
                 childParams.mParentVerificationParams = this;
-                this.mChildParams.add(childParams);
             }
             this.mVerificationState = new ArrayMap<>(mChildParams.size());
-            mObserver = parent.getObserver();
+            mObserver = parent.observer;
         }
 
         @Override
@@ -15150,31 +15128,26 @@
         private boolean mWaitForEnableRollbackToComplete;
         private int mRet;
 
-        VerificationParams(ActiveInstallSession activeInstallSession) {
-            super(activeInstallSession.getUser());
-            final PackageInstaller.SessionParams sessionParams =
-                    activeInstallSession.getSessionParams();
-            if (DEBUG_INSTANT) {
-                if ((sessionParams.installFlags
-                        & PackageManager.INSTALL_INSTANT_APP) != 0) {
-                    Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
-                }
-            }
+        VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
+                PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+                int installerUid, SigningDetails signingDetails, int sessionId) {
+            super(user);
+            origin = OriginInfo.fromStagedFile(stagedDir);
+            this.observer = observer;
+            installFlags = sessionParams.installFlags;
+            this.installSource = installSource;
+            packageAbiOverride = sessionParams.abiOverride;
             verificationInfo = new VerificationInfo(
                     sessionParams.originatingUri,
                     sessionParams.referrerUri,
                     sessionParams.originatingUid,
-                    activeInstallSession.getInstallerUid());
-            origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
-            observer = activeInstallSession.getObserver();
-            installFlags = sessionParams.installFlags;
-            installSource = activeInstallSession.getInstallSource();
-            packageAbiOverride = sessionParams.abiOverride;
-            signingDetails = activeInstallSession.getSigningDetails();
+                    installerUid
+            );
+            this.signingDetails = signingDetails;
             requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
             mDataLoaderType = (sessionParams.dataLoaderParams != null)
                     ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
-            mSessionId = activeInstallSession.getSessionId();
+            mSessionId = sessionId;
         }
 
         @Override
@@ -16793,7 +16766,7 @@
                 reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
                 reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
 
-                res.removedInfo.broadcastWhitelist = mAppsFilter.getVisibilityWhitelist(
+                res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(
                                 reconciledPkg.pkgSetting, request.mAllUsers, mSettings.mPackages);
                 if (reconciledPkg.prepareResult.system) {
                     // Remove existing system package
@@ -18723,7 +18696,7 @@
         boolean isStaticSharedLib;
         // a two dimensional array mapping userId to the set of appIds that can receive notice
         // of package changes
-        SparseArray<int[]> broadcastWhitelist;
+        SparseArray<int[]> broadcastAllowList;
         // Clean up resources deleted packages.
         InstallArgs args = null;
 
@@ -18746,9 +18719,9 @@
             extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
             extras.putBoolean(Intent.EXTRA_REPLACING, true);
             packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras,
-                    0, null /*targetPackage*/, null, null, null, broadcastWhitelist);
+                    0, null /*targetPackage*/, null, null, null, broadcastAllowList);
             packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
-                    extras, 0, null /*targetPackage*/, null, null, null, broadcastWhitelist);
+                    extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList);
             packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
                     removedPackage, null, null, null, null /* broadcastWhitelist */);
             if (installerPackageName != null) {
@@ -18780,7 +18753,7 @@
             if (removedPackage != null) {
                 packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
                     removedPackage, extras, 0, null /*targetPackage*/, null,
-                    broadcastUsers, instantUserIds, broadcastWhitelist);
+                    broadcastUsers, instantUserIds, broadcastAllowList);
                 if (installerPackageName != null) {
                     packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
                             removedPackage, extras, 0 /*flags*/,
@@ -18789,7 +18762,7 @@
                 if (dataRemoved && !isRemovedPackageSystemUpdate) {
                     packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
                             removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
-                            null, broadcastUsers, instantUserIds, broadcastWhitelist);
+                            null, broadcastUsers, instantUserIds, broadcastAllowList);
                     packageSender.notifyPackageRemoved(removedPackage, removedUid);
                 }
             }
@@ -18802,7 +18775,7 @@
 
                 packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
                         null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
-                        null, null, broadcastUsers, instantUserIds, broadcastWhitelist);
+                        null, null, broadcastUsers, instantUserIds, broadcastAllowList);
             }
         }
 
@@ -19301,6 +19274,13 @@
         final int flags = action.flags;
         final boolean systemApp = isSystemApp(ps);
 
+        // We need to get the permission state before package state is (potentially) destroyed.
+        final SparseBooleanArray hadSuspendAppsPermission = new SparseBooleanArray();
+        for (int userId : allUserHandles) {
+            hadSuspendAppsPermission.put(userId, checkPermission(Manifest.permission.SUSPEND_APPS,
+                    packageName, userId) == PERMISSION_GRANTED);
+        }
+
         final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
 
         if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
@@ -19367,8 +19347,7 @@
             affectedUserIds = resolveUserIds(userId);
         }
         for (final int affectedUserId : affectedUserIds) {
-            if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS,
-                    affectedUserId)) {
+            if (hadSuspendAppsPermission.get(affectedUserId)) {
                 unsuspendForSuspendingPackage(packageName, affectedUserId);
                 removeAllDistractingPackageRestrictions(affectedUserId);
             }
@@ -20835,6 +20814,11 @@
         return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName());
     }
 
+    public String getOverlayConfigSignaturePackageName() {
+        return ensureSystemPackageName(SystemConfig.getInstance()
+                .getOverlayConfigSignaturePackage());
+    }
+
     @Nullable
     private String getRetailDemoPackageName() {
         final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
@@ -21141,8 +21125,8 @@
                 pkgSetting.setEnabled(newState, userId, callingPackage);
                 if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
                         || newState == COMPONENT_ENABLED_STATE_DISABLED)
-                        && pkgSetting.getPermissionsState().hasPermission(
-                                Manifest.permission.SUSPEND_APPS, userId)) {
+                        && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+                        == PERMISSION_GRANTED) {
                     // This app should not generally be allowed to get disabled by the UI, but if it
                     // ever does, we don't want to end up with some of the user's apps permanently
                     // suspended.
@@ -21294,17 +21278,17 @@
         final boolean isInstantApp = isInstantApp(packageName, userId);
         final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
         final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
-        final SparseArray<int[]> broadcastWhitelist;
+        final SparseArray<int[]> broadcastAllowList;
         synchronized (mLock) {
             PackageSetting setting = getPackageSettingInternal(packageName, Process.SYSTEM_UID);
             if (setting == null) {
                 return;
             }
-            broadcastWhitelist = isInstantApp ? null : mAppsFilter.getVisibilityWhitelist(setting,
+            broadcastAllowList = isInstantApp ? null : mAppsFilter.getVisibilityAllowList(setting,
                     userIds, mSettings.mPackages);
         }
         sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, flags, null, null,
-                userIds, instantUserIds, broadcastWhitelist);
+                userIds, instantUserIds, broadcastAllowList);
     }
 
     @Override
@@ -23457,11 +23441,7 @@
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
         final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
-                installSource, volumeUuid, user,
-                packageAbiOverride, null /*grantedPermissions*/,
-                null /*whitelistedRestrictedPermissions*/, MODE_DEFAULT /* autoRevokePermissions */,
-                PackageParser.SigningDetails.UNKNOWN,
-                PackageManager.INSTALL_REASON_UNKNOWN, DataLoaderType.NONE);
+                installSource, volumeUuid, user, packageAbiOverride);
         params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -23663,8 +23643,20 @@
         }
     }
 
-    void onNewUserCreated(final int userId) {
-        mPermissionManager.onNewUserCreated(userId);
+    void onNewUserCreated(@UserIdInt int userId, boolean convertedFromPreCreated) {
+        if (DEBUG_PERMISSIONS) {
+            Slog.d(TAG, "onNewUserCreated(id=" + userId
+                    + ", convertedFromPreCreated=" + convertedFromPreCreated + ")");
+        }
+        if (!convertedFromPreCreated) {
+            mPermissionManager.onNewUserCreated(userId);
+            return;
+        }
+        if (!readPermissionStateForUser(userId)) {
+            // Could not read the existing permissions, re-grant them.
+            Slog.i(TAG, "re-granting permissions for pre-created user " + userId);
+            mPermissionManager.onNewUserCreated(userId);
+        }
     }
 
     boolean readPermissionStateForUser(@UserIdInt int userId) {
@@ -24354,6 +24346,8 @@
                     return TextUtils.isEmpty(mRetailDemoPackage)
                             ? ArrayUtils.emptyArray(String.class)
                             : new String[] {mRetailDemoPackage};
+                case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
+                    return filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
                 default:
                     return ArrayUtils.emptyArray(String.class);
             }
@@ -25707,71 +25701,6 @@
     public List<String> getMimeGroup(String packageName, String mimeGroup) {
         return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
     }
-
-    // TODO(samiul): Get rid of this class. The callers can create InstallParams and
-    //  VerificationParams directly.
-    static class ActiveInstallSession {
-        private final String mPackageName;
-        private final File mStagedDir;
-        private final IPackageInstallObserver2 mObserver;
-        private final int mSessionId;
-        private final PackageInstaller.SessionParams mSessionParams;
-        private final int mInstallerUid;
-        @NonNull private final InstallSource mInstallSource;
-        private final UserHandle mUser;
-        private final SigningDetails mSigningDetails;
-
-        ActiveInstallSession(String packageName, File stagedDir, IPackageInstallObserver2 observer,
-                int sessionId, PackageInstaller.SessionParams sessionParams, int installerUid,
-                InstallSource installSource, UserHandle user, SigningDetails signingDetails) {
-            mPackageName = packageName;
-            mStagedDir = stagedDir;
-            mObserver = observer;
-            mSessionId = sessionId;
-            mSessionParams = sessionParams;
-            mInstallerUid = installerUid;
-            mInstallSource = Preconditions.checkNotNull(installSource);
-            mUser = user;
-            mSigningDetails = signingDetails;
-        }
-
-        public String getPackageName() {
-            return mPackageName;
-        }
-
-        public File getStagedDir() {
-            return mStagedDir;
-        }
-
-        public IPackageInstallObserver2 getObserver() {
-            return mObserver;
-        }
-
-        public int getSessionId() {
-            return mSessionId;
-        }
-
-        public PackageInstaller.SessionParams getSessionParams() {
-            return mSessionParams;
-        }
-
-        public int getInstallerUid() {
-            return mInstallerUid;
-        }
-
-        @NonNull
-        public InstallSource getInstallSource() {
-            return mInstallSource;
-        }
-
-        public UserHandle getUser() {
-            return mUser;
-        }
-
-        public SigningDetails getSigningDetails() {
-            return mSigningDetails;
-        }
-    }
 }
 
 interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 03f4708..de0e4b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -488,6 +488,18 @@
     }
 
     /**
+     * Returns true if the signature set of the package is identical to the specified signature
+     * set or if the signing details of the package are unknown.
+     */
+    public static boolean comparePackageSignatures(PackageSetting pkgSetting,
+            Signature[] signatures) {
+        return pkgSetting.signatures.mSigningDetails
+                == PackageParser.SigningDetails.UNKNOWN
+                || compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, signatures)
+                == PackageManager.SIGNATURE_MATCH;
+    }
+
+    /**
      * Used for backward compatibility to make sure any packages with
      * certificate chains get upgraded to the new style. {@code existingSigs}
      * will be in the old format (since they were stored on disk from before the
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index f16b5b4..700f7be 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -108,6 +108,7 @@
 import com.android.internal.util.StatLogger;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.pm.ShortcutUser.PackageWithUser;
 import com.android.server.uri.UriGrantsManagerInternal;
 
@@ -259,7 +260,8 @@
     private static final int PACKAGE_MATCH_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE
                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                    | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+                    | PackageManager.MATCH_UNINSTALLED_PACKAGES
+                    | PackageManager.MATCH_DISABLED_COMPONENTS;
 
     private static final int SYSTEM_APP_MASK =
             ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
@@ -277,12 +279,6 @@
         }
     };
 
-    private static Predicate<ResolveInfo> ACTIVITY_NOT_SYSTEM_NOR_ENABLED = (ri) -> {
-        final ApplicationInfo ai = ri.activityInfo.applicationInfo;
-        final boolean isSystemApp = ai != null && (ai.flags & SYSTEM_APP_MASK) != 0;
-        return !isSystemApp && !ri.activityInfo.enabled;
-    };
-
     private static Predicate<ResolveInfo> ACTIVITY_NOT_INSTALLED = (ri) ->
             !isInstalled(ri.activityInfo);
 
@@ -614,13 +610,13 @@
         }
 
         @Override
-        public void onStopUser(int userHandle) {
-            mService.handleStopUser(userHandle);
+        public void onUserStopping(@NonNull TargetUser user) {
+            mService.handleStopUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onUnlockUser(int userId) {
-            mService.handleUnlockUser(userId);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mService.handleUnlockUser(user.getUserIdentifier());
         }
     }
 
@@ -3684,10 +3680,8 @@
         final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
-            return mIPackageManager.getPackageInfo(
-                    packageName, PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS
-                            | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0),
-                    userId);
+            return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
+                    | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0), userId);
         } catch (RemoteException e) {
             // Shouldn't happen.
             Slog.wtf(TAG, "RemoteException", e);
@@ -3720,8 +3714,7 @@
         final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
-            return mIPackageManager.getApplicationInfo(packageName,
-                    PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+            return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
         } catch (RemoteException e) {
             // Shouldn't happen.
             Slog.wtf(TAG, "RemoteException", e);
@@ -3752,9 +3745,8 @@
         final long start = getStatStartTime();
         final long token = injectClearCallingIdentity();
         try {
-            return mIPackageManager.getActivityInfo(activity, (PACKAGE_MATCH_FLAGS
-                    | PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_META_DATA),
-                    userId);
+            return mIPackageManager.getActivityInfo(activity,
+                    PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA, userId);
         } catch (RemoteException e) {
             // Shouldn't happen.
             Slog.wtf(TAG, "RemoteException", e);
@@ -3799,8 +3791,7 @@
     List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId)
             throws RemoteException {
         final ParceledListSlice<PackageInfo> parceledList =
-                mIPackageManager.getInstalledPackages(
-                        PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+                mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId);
         if (parceledList == null) {
             return Collections.emptyList();
         }
@@ -3835,6 +3826,41 @@
         return (ai != null) && ((ai.flags & flags) == flags);
     }
 
+    // Due to b/38267327, ActivityInfo.enabled may not reflect the current state of the component
+    // and we need to check the enabled state via PackageManager.getComponentEnabledSetting.
+    private boolean isEnabled(@Nullable ActivityInfo ai, int userId) {
+        if (ai == null) {
+            return false;
+        }
+
+        int enabledFlag;
+        final long token = injectClearCallingIdentity();
+        try {
+            enabledFlag = mIPackageManager.getComponentEnabledSetting(
+                    ai.getComponentName(), userId);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+            Slog.wtf(TAG, "RemoteException", e);
+            return false;
+        } finally {
+            injectRestoreCallingIdentity(token);
+        }
+
+        if ((enabledFlag == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && ai.enabled)
+                || enabledFlag == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean isSystem(@Nullable ActivityInfo ai) {
+        return (ai != null) && isSystem(ai.applicationInfo);
+    }
+
+    private static boolean isSystem(@Nullable ApplicationInfo ai) {
+        return (ai != null) && (ai.flags & SYSTEM_APP_MASK) != 0;
+    }
+
     private static boolean isInstalled(@Nullable ApplicationInfo ai) {
         return (ai != null) && ai.enabled && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
     }
@@ -3899,12 +3925,6 @@
         return intent;
     }
 
-    private static boolean isSystemApp(@Nullable final ApplicationInfo ai) {
-        final int systemAppMask =
-                ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-        return ai != null && ((ai.flags & systemAppMask) != 0);
-    }
-
     /**
      * Same as queryIntentActivitiesAsUser, except it makes sure the package is installed,
      * and only returns exported activities.
@@ -3937,7 +3957,10 @@
         }
         // Make sure the package is installed.
         resolved.removeIf(ACTIVITY_NOT_INSTALLED);
-        resolved.removeIf(ACTIVITY_NOT_SYSTEM_NOR_ENABLED);
+        resolved.removeIf((ri) -> {
+            final ActivityInfo ai = ri.activityInfo;
+            return !isSystem(ai) && !isEnabled(ai, userId);
+        });
         if (exportedOnly) {
             resolved.removeIf(ACTIVITY_NOT_EXPORTED);
         }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 89bdb3e..f9bf54a 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -322,9 +322,6 @@
         }
         final long activeVersion = activePackage.applicationInfo.longVersionCode;
         if (activeVersion != session.params.requiredInstalledVersionCode) {
-            if (!mApexManager.abortStagedSession(session.sessionId)) {
-                Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
-            }
             throw new PackageManagerException(
                     SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                     "Installed version of APEX package " + activePackage.packageName
@@ -338,14 +335,11 @@
             throws PackageManagerException {
         final long activeVersion = activePackage.applicationInfo.longVersionCode;
         final long newVersionCode = newPackage.applicationInfo.longVersionCode;
-        boolean isAppDebuggable = (activePackage.applicationInfo.flags
+        final boolean isAppDebuggable = (activePackage.applicationInfo.flags
                 & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
                 session.params.installFlags, isAppDebuggable);
         if (activeVersion > newVersionCode && !allowsDowngrade) {
-            if (!mApexManager.abortStagedSession(session.sessionId)) {
-                Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
-            }
             throw new PackageManagerException(
                     SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                     "Downgrade of APEX package " + newPackage.packageName
@@ -835,37 +829,6 @@
         return null;
     }
 
-    private void verifyApksInSession(PackageInstallerSession session)
-            throws PackageManagerException {
-
-        final PackageInstallerSession apksToVerify = extractApksInSession(
-                session,  /* preReboot */ true);
-        if (apksToVerify == null) {
-            return;
-        }
-
-        final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
-                (Intent result) -> {
-                    int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                            PackageInstaller.STATUS_FAILURE);
-                    if (status != PackageInstaller.STATUS_SUCCESS) {
-                        final String errorMessage = result.getStringExtra(
-                                PackageInstaller.EXTRA_STATUS_MESSAGE);
-                        Slog.e(TAG, "Failure to verify APK staged session "
-                                + session.sessionId + " [" + errorMessage + "]");
-                        session.setStagedSessionFailed(
-                                SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, errorMessage);
-                        mPreRebootVerificationHandler.onPreRebootVerificationComplete(
-                                session.sessionId);
-                        return;
-                    }
-                    mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
-                            session.sessionId);
-                });
-
-        apksToVerify.commit(receiver.getIntentSender(), false);
-    }
-
     private void installApksInSession(@NonNull PackageInstallerSession session)
             throws PackageManagerException {
 
@@ -908,10 +871,21 @@
         mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId);
     }
 
-    private int parentOrOwnSessionId(PackageInstallerSession session) {
+    private int getSessionIdForParentOrSelf(PackageInstallerSession session) {
         return session.hasParentSessionId() ? session.getParentSessionId() : session.sessionId;
     }
 
+    private PackageInstallerSession getParentSessionOrSelf(PackageInstallerSession session) {
+        return session.hasParentSessionId()
+                ? getStagedSession(session.getParentSessionId())
+                : session;
+    }
+
+    private boolean isRollback(PackageInstallerSession session) {
+        final PackageInstallerSession root = getParentSessionOrSelf(session);
+        return root.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
+    }
+
     /**
      * <p> Check if the session provided is non-overlapping with the active staged sessions.
      *
@@ -937,6 +911,8 @@
         boolean supportsCheckpoint = ((StorageManager) mContext.getSystemService(
                 Context.STORAGE_SERVICE)).isCheckpointSupported();
 
+        final boolean isRollback = isRollback(session);
+
         synchronized (mStagedSessions) {
             for (int i = 0; i < mStagedSessions.size(); i++) {
                 final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
@@ -951,8 +927,8 @@
                 }
                 // Check if stagedSession has an active parent session or not
                 if (stagedSession.hasParentSessionId()) {
-                    int parentId = stagedSession.getParentSessionId();
-                    PackageInstallerSession parentSession = mStagedSessions.get(parentId);
+                    final int parentId = stagedSession.getParentSessionId();
+                    final PackageInstallerSession parentSession = mStagedSessions.get(parentId);
                     if (parentSession == null || parentSession.isStagedAndInTerminalState()
                             || parentSession.isDestroyed()) {
                         // Parent session has been abandoned or terminated already
@@ -968,21 +944,37 @@
                     continue;
                 }
 
-                // If session is not among the active sessions, then it cannot have same package
-                // name as any of the active sessions.
+                // New session cannot have same package name as one of the active sessions
                 if (session.getPackageName().equals(stagedSession.getPackageName())) {
-                    throw new PackageManagerException(
-                            PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
-                            "Package: " + session.getPackageName() + " in session: "
-                                    + session.sessionId + " has been staged already by session: "
-                                    + stagedSession.sessionId, null);
+                    if (isRollback) {
+                        // If the new session is a rollback, then it gets priority. The existing
+                        // session is failed to unblock rollback.
+                        final PackageInstallerSession root = getParentSessionOrSelf(stagedSession);
+                        if (!ensureActiveApexSessionIsAborted(root)) {
+                            Slog.e(TAG, "Failed to abort apex session " + root.sessionId);
+                            // Safe to ignore active apex session abort failure since session
+                            // will be marked failed on next step and staging directory for session
+                            // will be deleted.
+                        }
+                        root.setStagedSessionFailed(
+                                SessionInfo.STAGED_SESSION_OTHER_ERROR,
+                                "Session was blocking rollback session: " + session.sessionId);
+                        Slog.i(TAG, "Session " + root.sessionId + " is marked failed due to "
+                                + "blocking rollback session: " + session.sessionId);
+                    } else {
+                        throw new PackageManagerException(
+                                PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+                                "Package: " + session.getPackageName() + " in session: "
+                                        + session.sessionId + " has been staged already by session:"
+                                        + " " + stagedSession.sessionId, null);
+                    }
                 }
 
                 // Staging multiple root sessions is not allowed if device doesn't support
                 // checkpoint. If session and stagedSession do not have common ancestor, they are
                 // from two different root sessions.
-                if (!supportsCheckpoint
-                        && parentOrOwnSessionId(session) != parentOrOwnSessionId(stagedSession)) {
+                if (!supportsCheckpoint && getSessionIdForParentOrSelf(session)
+                        != getSessionIdForParentOrSelf(stagedSession)) {
                     throw new PackageManagerException(
                             PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
                             "Cannot stage multiple sessions without checkpoint support", null);
@@ -1042,23 +1034,11 @@
 
         // A session could be marked ready once its pre-reboot verification ends
         if (session.isStagedSessionReady()) {
-            if (sessionContainsApex(session)) {
-                try {
-                    ApexSessionInfo apexSession =
-                            mApexManager.getStagedSessionInfo(session.sessionId);
-                    if (apexSession == null || isApexSessionFinalized(apexSession)) {
-                        Slog.w(TAG,
-                                "Cannot abort session " + session.sessionId
-                                        + " because it is not active.");
-                    } else {
-                        mApexManager.abortStagedSession(session.sessionId);
-                    }
-                } catch (Exception e) {
-                    // Failed to contact apexd service. The apex might still be staged. We can still
-                    // safely cleanup the staged session since pre-reboot verification is complete.
-                    // Also, cleaning up the stageDir prevents the apex from being activated.
-                    Slog.w(TAG, "Could not contact apexd to abort staged session " + sessionId);
-                }
+            if (!ensureActiveApexSessionIsAborted(session)) {
+                // Failed to ensure apex session is aborted, so it can still be staged. We can still
+                // safely cleanup the staged session since pre-reboot verification is complete.
+                // Also, cleaning up the stageDir prevents the apex from being activated.
+                Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
             }
         }
 
@@ -1068,6 +1048,22 @@
         return true;
     }
 
+    /**
+     * Ensure that there is no active apex session staged in apexd for the given session.
+     *
+     * @return returns true if it is ensured that there is no active apex session, otherwise false
+     */
+    private boolean ensureActiveApexSessionIsAborted(PackageInstallerSession session) {
+        if (!sessionContainsApex(session)) {
+            return true;
+        }
+        final ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
+        if (apexSession == null || isApexSessionFinalized(apexSession)) {
+            return true;
+        }
+        return mApexManager.abortStagedSession(session.sessionId);
+    }
+
     private boolean isApexSessionFinalized(ApexSessionInfo session) {
         /* checking if the session is in a final state, i.e., not active anymore */
         return session.isUnknown || session.isActivationFailed || session.isSuccess
@@ -1294,8 +1290,8 @@
                         + sessionId);
                 return;
             }
-            if (session.isDestroyed()) {
-                // No point in running verification on a destroyed session
+            if (session.isDestroyed() || session.isStagedSessionFailed()) {
+                // No point in running verification on a destroyed/failed session
                 onPreRebootVerificationComplete(sessionId);
                 return;
             }
@@ -1348,6 +1344,17 @@
             obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
         }
 
+        private void onPreRebootVerificationFailure(PackageInstallerSession session,
+                @SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) {
+            if (!ensureActiveApexSessionIsAborted(session)) {
+                Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
+                // Safe to ignore active apex session abortion failure since session will be marked
+                // failed on next step and staging directory for session will be deleted.
+            }
+            session.setStagedSessionFailed(errorCode, errorMessage);
+            onPreRebootVerificationComplete(session.sessionId);
+        }
+
         // Things to do when pre-reboot verification completes for a particular sessionId
         private void onPreRebootVerificationComplete(int sessionId) {
             // Remove it from mVerificationRunning so that verification is considered complete
@@ -1432,8 +1439,7 @@
                         validateApexSignature(apexPackages.get(i));
                     }
                 } catch (PackageManagerException e) {
-                    session.setStagedSessionFailed(e.error, e.getMessage());
-                    onPreRebootVerificationComplete(session.sessionId);
+                    onPreRebootVerificationFailure(session, e.error, e.getMessage());
                     return;
                 }
 
@@ -1460,16 +1466,42 @@
             try {
                 Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
                         + session.sessionId + " by performing a dry-run install");
-
                 // verifyApksInSession will notify the handler when APK verification is complete
                 verifyApksInSession(session);
-                // TODO(b/118865310): abort the session on apexd.
             } catch (PackageManagerException e) {
-                session.setStagedSessionFailed(e.error, e.getMessage());
-                onPreRebootVerificationComplete(session.sessionId);
+                onPreRebootVerificationFailure(session, e.error, e.getMessage());
             }
         }
 
+        private void verifyApksInSession(PackageInstallerSession session)
+                throws PackageManagerException {
+
+            final PackageInstallerSession apksToVerify = extractApksInSession(
+                    session,  /* preReboot */ true);
+            if (apksToVerify == null) {
+                return;
+            }
+
+            final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
+                    (Intent result) -> {
+                        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                                PackageInstaller.STATUS_FAILURE);
+                        if (status != PackageInstaller.STATUS_SUCCESS) {
+                            final String errorMessage = result.getStringExtra(
+                                    PackageInstaller.EXTRA_STATUS_MESSAGE);
+                            Slog.e(TAG, "Failure to verify APK staged session "
+                                    + session.sessionId + " [" + errorMessage + "]");
+                            onPreRebootVerificationFailure(session,
+                                    SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage);
+                            return;
+                        }
+                        mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
+                                session.sessionId);
+                    });
+
+            apksToVerify.commit(receiver.getIntentSender(), false);
+        }
+
         /**
          * Pre-reboot verification state for wrapping up:
          * <p><ul>
@@ -1487,9 +1519,8 @@
             } catch (Exception e) {
                 // Failed to get hold of StorageManager
                 Slog.e(TAG, "Failed to get hold of StorageManager", e);
-                session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
+                onPreRebootVerificationFailure(session, SessionInfo.STAGED_SESSION_UNKNOWN,
                         "Failed to get hold of StorageManager");
-                onPreRebootVerificationComplete(session.sessionId);
                 return;
             }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b0d3d53..e3bee72 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -110,6 +110,7 @@
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.am.UserState;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.utils.TimingsTraceAndSlog;
@@ -553,9 +554,9 @@
         }
 
         @Override
-        public void onStartUser(@UserIdInt int userId) {
+        public void onUserStarting(@NonNull TargetUser targetUser) {
             synchronized (mUms.mUsersLock) {
-                final UserData user = mUms.getUserDataLU(userId);
+                final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
                 if (user != null) {
                     user.startRealtime = SystemClock.elapsedRealtime();
                 }
@@ -563,9 +564,9 @@
         }
 
         @Override
-        public void onUnlockUser(@UserIdInt int userId) {
+        public void onUserUnlocking(@NonNull TargetUser targetUser) {
             synchronized (mUms.mUsersLock) {
-                final UserData user = mUms.getUserDataLU(userId);
+                final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
                 if (user != null) {
                     user.unlockRealtime = SystemClock.elapsedRealtime();
                 }
@@ -573,9 +574,9 @@
         }
 
         @Override
-        public void onStopUser(@UserIdInt int userId) {
+        public void onUserStopping(@NonNull TargetUser targetUser) {
             synchronized (mUms.mUsersLock) {
-                final UserData user = mUms.getUserDataLU(userId);
+                final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
                 if (user != null) {
                     user.startRealtime = 0;
                     user.unlockRealtime = 0;
@@ -3496,7 +3497,7 @@
             }
 
             t.traceBegin("PM.onNewUserCreated-" + userId);
-            mPm.onNewUserCreated(userId);
+            mPm.onNewUserCreated(userId, /* convertedFromPreCreated= */ false);
             t.traceEnd();
             if (preCreate) {
                 // Must start user (which will be stopped right away, through
@@ -3569,10 +3570,7 @@
             writeUserListLP();
         }
         updateUserIds();
-        if (!mPm.readPermissionStateForUser(preCreatedUser.id)) {
-            // Could not read the existing permissions, re-grant them.
-            mPm.onNewUserCreated(preCreatedUser.id);
-        }
+        mPm.onNewUserCreated(preCreatedUser.id, /* convertedFromPreCreated= */ true);
         dispatchUserAdded(preCreatedUser);
         return preCreatedUser;
     }
diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS
index fcc1f6c..5a4431e 100644
--- a/services/core/java/com/android/server/pm/dex/OWNERS
+++ b/services/core/java/com/android/server/pm/dex/OWNERS
@@ -1,4 +1,2 @@
-agampe@google.com
 calin@google.com
 ngeoffray@google.com
-sehr@google.com
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 6e0efb0..be93b8f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -137,7 +137,6 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerService;
 import com.android.server.pm.ApexManager;
 import com.android.server.pm.PackageManagerServiceUtils;
 import com.android.server.pm.PackageSetting;
@@ -922,16 +921,6 @@
         }
 
         final int uid = UserHandle.getUid(userId, pkg.getUid());
-
-        try {
-            enforceCrossUserOrProfilePermission(Binder.getCallingUid(), UserHandle.getUserId(uid),
-                    false, false, "checkPermissionInternal");
-        } catch (Exception e) {
-            EventLog.writeEvent(0x534e4554, "153996875", "checkPermission", uid);
-
-            throw e;
-        }
-
         final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
                 pkg.getPackageName());
         if (ps == null) {
@@ -4399,7 +4388,7 @@
         }
         final int callingUserId = UserHandle.getUserId(callingUid);
         if (hasCrossUserPermission(
-                Binder.getCallingPid(), callingUid, callingUserId, userId, requireFullPermission,
+                callingUid, callingUserId, userId, requireFullPermission,
                 requirePermissionWhenSameUser)) {
             return;
         }
@@ -4426,54 +4415,37 @@
     private void enforceCrossUserOrProfilePermission(int callingUid, int userId,
             boolean requireFullPermission, boolean checkShell,
             String message) {
-        int callingPid = Binder.getCallingPid();
-        final int callingUserId = UserHandle.getUserId(callingUid);
-
         if (userId < 0) {
             throw new IllegalArgumentException("Invalid userId " + userId);
         }
-
-        if (callingUserId == userId) {
+        if (checkShell) {
+            PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
+                    UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+        }
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
+                /*requirePermissionWhenSameUser= */ false)) {
             return;
         }
-
-        // Prevent endless loop between when checking permission while checking a permission
-        if (callingPid == ActivityManagerService.MY_PID) {
+        final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
+        if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
+                mContext,
+                android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+                PermissionChecker.PID_UNKNOWN,
+                callingUid,
+                mPackageManagerInt.getPackage(callingUid).getPackageName())
+                == PermissionChecker.PERMISSION_GRANTED) {
             return;
         }
-
-        long token = Binder.clearCallingIdentity();
-        try {
-            if (checkShell) {
-                PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
-                        UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
-            }
-            if (hasCrossUserPermission(callingPid, callingUid, callingUserId, userId,
-                    requireFullPermission, /*requirePermissionWhenSameUser= */ false)) {
-                return;
-            }
-            final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
-            if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
-                    mContext,
-                    android.Manifest.permission.INTERACT_ACROSS_PROFILES,
-                    PermissionChecker.PID_UNKNOWN,
-                    callingUid,
-                    mPackageManagerInt.getPackage(callingUid).getPackageName())
-                    == PermissionChecker.PERMISSION_GRANTED) {
-                return;
-            }
-
-            String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
-                    message, requireFullPermission, isSameProfileGroup);
-            Slog.w(TAG, errorMessage);
-            throw new SecurityException(errorMessage);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
+                message, requireFullPermission, isSameProfileGroup);
+        Slog.w(TAG, errorMessage);
+        throw new SecurityException(errorMessage);
     }
 
-    private boolean hasCrossUserPermission(int callingPid, int callingUid, int callingUserId,
-            int userId, boolean requireFullPermission, boolean requirePermissionWhenSameUser) {
+    private boolean hasCrossUserPermission(
+            int callingUid, int callingUserId, int userId, boolean requireFullPermission,
+            boolean requirePermissionWhenSameUser) {
         if (!requirePermissionWhenSameUser && userId == callingUserId) {
             return true;
         }
@@ -4481,11 +4453,15 @@
             return true;
         }
         if (requireFullPermission) {
-            return mContext.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+            return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
         }
-        return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS,
-                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+        return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
+    }
+
+    private boolean hasPermission(String permission) {
+        return mContext.checkCallingOrSelfPermission(permission)
+                == PackageManager.PERMISSION_GRANTED;
     }
 
     private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 65dc320..c0d71ac 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -18,6 +18,14 @@
             ]
         },
         {
+            "name": "CtsAppSecurityHostTestCases",
+            "options": [
+                {
+                    "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
+                }
+            ]
+        },
+        {
             "name": "CtsPermission2TestCases",
             "options": [
                 {
@@ -29,17 +37,6 @@
             ]
         },
         {
-            "name": "CtsPermissionHostTestCases"
-        },
-        {
-            "name": "CtsAppSecurityHostTestCases",
-            "options": [
-                {
-                    "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
-                }
-            ]
-        },
-        {
             "name": "CtsStatsdHostTestCases",
             "options": [
                 {
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 37f088b..4d48a2e 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -67,6 +67,7 @@
 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.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
@@ -347,7 +348,11 @@
     }
 
     @Override
-    public void onStartUser(@UserIdInt int userId) {
+    public void onUserStarting(@NonNull TargetUser user) {
+        onStartUser(user.getUserIdentifier());
+    }
+
+    private void onStartUser(@UserIdInt int userId) {
         if (DEBUG) Slog.i(LOG_TAG, "onStartUser(" + userId + ")");
 
         if (isStarted(userId)) {
@@ -373,11 +378,11 @@
     }
 
     @Override
-    public void onStopUser(@UserIdInt int userId) {
-        if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + userId + ")");
+    public void onUserStopping(@NonNull TargetUser user) {
+        if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + user + ")");
 
         synchronized (mLock) {
-            mIsStarted.delete(userId);
+            mIsStarted.delete(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a2b46a0..f9a49c9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -493,9 +493,6 @@
     private boolean mProximityPositive;
 
     // Screen brightness setting limits.
-    private float mScreenBrightnessSettingMinimum;
-    private float mScreenBrightnessSettingMaximum;
-    private float mScreenBrightnessSettingDefault;
     public final float mScreenBrightnessMinimum;
     public final float mScreenBrightnessMaximum;
     public final float mScreenBrightnessDefault;
@@ -1030,14 +1027,6 @@
             mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
             mAttentionDetector.systemReady(mContext);
 
-            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-            mScreenBrightnessSettingMinimum = pm.getBrightnessConstraint(
-                    PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
-            mScreenBrightnessSettingMaximum = pm.getBrightnessConstraint(
-                    PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
-            mScreenBrightnessSettingDefault = pm.getBrightnessConstraint(
-                    PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT);
-
             SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
 
             // The notifier runs on the system server's main looper so as not to interfere
@@ -2818,7 +2807,7 @@
                 // Keep the brightness steady during boot. This requires the
                 // bootloader brightness and the default brightness to be identical.
                 autoBrightness = false;
-                screenBrightnessOverride = mScreenBrightnessSettingDefault;
+                screenBrightnessOverride = mScreenBrightnessDefault;
             } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                 autoBrightness = false;
                 screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
@@ -3869,9 +3858,9 @@
             pw.println("  mDrawWakeLockOverrideFromSidekick=" + mDrawWakeLockOverrideFromSidekick);
             pw.println("  mDozeScreenBrightnessOverrideFromDreamManager="
                     + mDozeScreenBrightnessOverrideFromDreamManager);
-            pw.println("  mScreenBrightnessSettingMinimumFloat=" + mScreenBrightnessSettingMinimum);
-            pw.println("  mScreenBrightnessSettingMaximumFloat=" + mScreenBrightnessSettingMaximum);
-            pw.println("  mScreenBrightnessSettingDefaultFloat=" + mScreenBrightnessSettingDefault);
+            pw.println("  mScreenBrightnessMinimum=" + mScreenBrightnessMinimum);
+            pw.println("  mScreenBrightnessMaximum=" + mScreenBrightnessMaximum);
+            pw.println("  mScreenBrightnessDefault=" + mScreenBrightnessDefault);
             pw.println("  mDoubleTapWakeEnabled=" + mDoubleTapWakeEnabled);
             pw.println("  mIsVrModeEnabled=" + mIsVrModeEnabled);
             pw.println("  mForegroundProfile=" + mForegroundProfile);
@@ -4228,15 +4217,15 @@
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
                             .SETTING_MINIMUM_FLOAT,
-                    mScreenBrightnessSettingMinimum);
+                    mScreenBrightnessMinimum);
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
                             .SETTING_MAXIMUM_FLOAT,
-                    mScreenBrightnessSettingMaximum);
+                    mScreenBrightnessMaximum);
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
                             .SETTING_DEFAULT_FLOAT,
-                    mScreenBrightnessSettingDefault);
+                    mScreenBrightnessDefault);
             proto.end(screenBrightnessSettingLimitsToken);
 
             proto.write(
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 392792d..a291cef 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -34,14 +34,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.PermissionChecker;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
-import android.database.CursorWindow;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
@@ -74,6 +71,7 @@
 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.permission.PermissionManagerServiceInternal;
 
 import java.io.ByteArrayOutputStream;
@@ -217,8 +215,8 @@
     }
 
     @Override
-    public void onStartUser(@UserIdInt int userId) {
-        maybeGrantDefaultRolesSync(userId);
+    public void onUserStarting(@NonNull TargetUser user) {
+        maybeGrantDefaultRolesSync(user.getUserIdentifier());
     }
 
     @MainThread
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
index ce1156b..04a5ca5 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerService.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -16,10 +16,12 @@
 
 package com.android.server.rollback;
 
+import android.annotation.NonNull;
 import android.content.Context;
 
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 /**
  * Service that manages APK level rollbacks. Publishes
@@ -43,8 +45,8 @@
     }
 
     @Override
-    public void onUserUnlocking(TargetUser user) {
-        mService.onUnlockUser(user.getUserHandle().getIdentifier());
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        mService.onUnlockUser(user.getUserIdentifier());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index fea68d3..7091c47 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -16,9 +16,7 @@
 
 package com.android.server.search;
 
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
+import android.annotation.NonNull;
 import android.app.ISearchManager;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
@@ -26,18 +24,14 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.service.voice.VoiceInteractionService;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -48,6 +42,7 @@
 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.statusbar.StatusBarManagerInternal;
 
 import java.io.FileDescriptor;
@@ -76,18 +71,13 @@
         }
 
         @Override
-        public void onUnlockUser(final int userId) {
-            mService.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mService.onUnlockUser(userId);
-                }
-            });
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mService.mHandler.post(() -> mService.onUnlockUser(user.getUserIdentifier()));
         }
 
         @Override
-        public void onCleanupUser(int userHandle) {
-            mService.onCleanupUser(userHandle);
+        public void onUserStopped(@NonNull TargetUser user) {
+            mService.onCleanupUser(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 7c8c494..4349ca4 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -26,6 +26,7 @@
 import static android.os.Process.SYSTEM_UID;
 
 import android.Manifest.permission;
+import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.app.slice.ISliceManager;
 import android.app.slice.SliceSpec;
@@ -59,10 +60,10 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
-import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -615,13 +616,13 @@
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
-            mService.onUnlockUser(userHandle);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mService.onUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onStopUser(int userHandle) {
-            mService.onStopUser(userHandle);
+        public void onUserStopping(@NonNull TargetUser user) {
+            mService.onStopUser(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 1707d95..363e86d 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -66,6 +66,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -118,14 +119,14 @@
         }
 
         @Override
-        public void onStartUser(int userId) {
-            processAnyPendingWork(userId);
+        public void onUserStarting(@NonNull TargetUser user) {
+            processAnyPendingWork(user.getUserIdentifier());
         }
 
         @Override
-        public void onUnlockUser(int userId) {
+        public void onUserUnlocking(@NonNull TargetUser user) {
             // Rebind if we failed earlier due to locked encrypted user
-            processAnyPendingWork(userId);
+            processAnyPendingWork(user.getUserIdentifier());
         }
 
         private void processAnyPendingWork(int userId) {
@@ -135,7 +136,9 @@
         }
 
         @Override
-        public void onStopUser(int userId) {
+        public void onUserStopping(@NonNull TargetUser user) {
+            int userId = user.getUserIdentifier();
+
             synchronized (mManagerService.mLock) {
                 UserState userState = mManagerService.peekUserStateLocked(userId);
                 if (userState != null) {
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index e0bac93..f39067b 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -58,6 +58,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -287,21 +288,21 @@
         }
 
         @Override
-        public void onStopUser(@UserIdInt int userHandle) {
+        public void onUserStopping(@NonNull TargetUser user) {
             if (DBG) {
-                Slog.d(TAG, "onStopUser userId: " + userHandle);
+                Slog.d(TAG, "onStopUser user: " + user);
             }
-            mService.onStopUser(userHandle);
+            mService.onStopUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onUnlockUser(@UserIdInt int userHandle) {
+        public void onUserUnlocking(@NonNull TargetUser user) {
             if(DBG) {
-                Slog.d(TAG, "onUnlockUser userId: " + userHandle);
+                Slog.d(TAG, "onUnlockUser userId: " + user);
             }
             // Called on the system server's main looper thread.
             // TODO: Dispatch this to a worker thread as needed.
-            mService.onUnlockUser(userHandle);
+            mService.onUnlockUser(user.getUserIdentifier());
         }
     }
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index fd3c1f9..6adff0d 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -17,6 +17,8 @@
 package com.android.server.trust;
 
 import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
@@ -71,6 +73,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -1042,28 +1045,28 @@
     // User lifecycle
 
     @Override
-    public void onStartUser(int userId) {
-        mHandler.obtainMessage(MSG_START_USER, userId, 0, null).sendToTarget();
+    public void onUserStarting(@NonNull TargetUser user) {
+        mHandler.obtainMessage(MSG_START_USER, user.getUserIdentifier(), 0, null).sendToTarget();
     }
 
     @Override
-    public void onCleanupUser(int userId) {
-        mHandler.obtainMessage(MSG_CLEANUP_USER, userId, 0, null).sendToTarget();
+    public void onUserStopped(@NonNull TargetUser user) {
+        mHandler.obtainMessage(MSG_CLEANUP_USER, user.getUserIdentifier(), 0, null).sendToTarget();
     }
 
     @Override
-    public void onSwitchUser(int userId) {
-        mHandler.obtainMessage(MSG_SWITCH_USER, userId, 0, null).sendToTarget();
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        mHandler.obtainMessage(MSG_SWITCH_USER, to.getUserIdentifier(), 0, null).sendToTarget();
     }
 
     @Override
-    public void onUnlockUser(int userId) {
-        mHandler.obtainMessage(MSG_UNLOCK_USER, userId, 0, null).sendToTarget();
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        mHandler.obtainMessage(MSG_UNLOCK_USER, user.getUserIdentifier(), 0, null).sendToTarget();
     }
 
     @Override
-    public void onStopUser(@UserIdInt int userId) {
-        mHandler.obtainMessage(MSG_STOP_USER, userId, 0, null).sendToTarget();
+    public void onUserStopping(@NonNull TargetUser user) {
+        mHandler.obtainMessage(MSG_STOP_USER, user.getUserIdentifier(), 0, null).sendToTarget();
     }
 
     // Plumbing
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 323ac7b..b3ec849 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -20,6 +20,7 @@
 import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
 import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
@@ -83,6 +84,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.IoThread;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -165,10 +167,10 @@
     }
 
     @Override
-    public void onUnlockUser(int userHandle) {
-        if (DEBUG) Slog.d(TAG, "onUnlockUser(userHandle=" + userHandle + ")");
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        if (DEBUG) Slog.d(TAG, "onUnlockUser(user=" + user + ")");
         synchronized (mLock) {
-            if (mCurrentUserId != userHandle) {
+            if (mCurrentUserId != user.getUserIdentifier()) {
                 return;
             }
             buildTvInputListLocked(mCurrentUserId, null);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 45689ce..ae873e2 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -19,6 +19,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
@@ -65,6 +66,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.utils.ManagedApplicationService;
 import com.android.server.utils.ManagedApplicationService.BinderChecker;
 import com.android.server.utils.ManagedApplicationService.LogEvent;
@@ -817,14 +819,14 @@
     }
 
     @Override
-    public void onStartUser(int userHandle) {
+    public void onUserStarting(@NonNull TargetUser user) {
         synchronized (mLock) {
             mComponentObserver.onUsersChanged();
         }
     }
 
     @Override
-    public void onSwitchUser(int userHandle) {
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         FgThread.getHandler().post(() -> {
             synchronized (mLock) {
                 mComponentObserver.onUsersChanged();
@@ -834,7 +836,7 @@
     }
 
     @Override
-    public void onStopUser(int userHandle) {
+    public void onUserStopping(@NonNull TargetUser user) {
         synchronized (mLock) {
             mComponentObserver.onUsersChanged();
         }
@@ -842,7 +844,7 @@
     }
 
     @Override
-    public void onCleanupUser(int userHandle) {
+    public void onUserStopped(@NonNull TargetUser user) {
         synchronized (mLock) {
             mComponentObserver.onUsersChanged();
         }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 90f87b1..2f695c6 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -105,6 +105,7 @@
 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.utils.TimingsTraceAndSlog;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -166,9 +167,9 @@
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
+        public void onUserUnlocking(@NonNull TargetUser user) {
             if (mService != null) {
-                mService.onUnlockUser(userHandle);
+                mService.onUnlockUser(user.getUserIdentifier());
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 024ef87..1b4fac6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -70,7 +70,7 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
 import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
 import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
@@ -168,7 +168,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutLocked;
+import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -587,8 +587,8 @@
      */
     private boolean mOccludesParent;
 
-    // The input dispatching timeout for this application token in nanoseconds.
-    long mInputDispatchingTimeoutNanos;
+    // The input dispatching timeout for this application token in milliseconds.
+    long mInputDispatchingTimeoutMillis;
 
     private boolean mShowWhenLocked;
     private boolean mInheritShownWhenLocked;
@@ -1245,7 +1245,7 @@
         if (oldParent == null && newParent != null) {
             // First time we are adding the activity to the system.
             mVoiceInteraction = newTask.voiceSession != null;
-            mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L;
+            mInputDispatchingTimeoutMillis = getInputDispatchingTimeoutMillisLocked(this);
 
             // TODO(b/36505427): Maybe this call should be moved inside
             // updateOverrideConfiguration()
@@ -1683,7 +1683,7 @@
         if (options != null) {
             final boolean useLockTask = options.getLockTaskMode();
             if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
-                lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+                lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
             }
         }
         return lockTaskLaunchMode;
@@ -2865,7 +2865,7 @@
 
         if (hasProcess()) {
             if (removeFromApp) {
-                app.removeActivity(this);
+                app.removeActivity(this, true /* keepAssociation */);
                 if (!app.hasActivities()) {
                     mAtmService.clearHeavyWeightProcessIfEquals(app);
                     // Update any services we are bound to that might care about whether
@@ -2914,7 +2914,7 @@
                 setState(DESTROYED,
                         "destroyActivityLocked. not finishing or skipping destroy");
                 if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + this);
-                app = null;
+                detachFromProcess();
             }
         } else {
             // Remove this record from the history.
@@ -2963,13 +2963,20 @@
         }
         setState(DESTROYED, "removeFromHistory");
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
-        app = null;
+        detachFromProcess();
         removeAppTokenFromDisplay();
 
         cleanUpActivityServices();
         removeUriPermissionsLocked();
     }
 
+    void detachFromProcess() {
+        if (app != null) {
+            app.removeActivity(this, false /* keepAssociation */);
+        }
+        app = null;
+    }
+
     void makeFinishingLocked() {
         if (finishing) {
             return;
@@ -3019,7 +3026,7 @@
         if (setState) {
             setState(DESTROYED, "cleanUp");
             if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + this);
-            app = null;
+            detachFromProcess();
         }
 
         // Inform supervisor the activity has been removed.
@@ -3160,6 +3167,64 @@
         mServiceConnectionsHolder = null;
     }
 
+    /**
+     * Detach this activity from process and clear the references to it. If the activity is
+     * finishing or has no saved state or crashed many times, it will also be removed from history.
+     */
+    void handleAppDied() {
+        final boolean remove;
+        if ((mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
+                || mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
+                && launchCount < 3 && !finishing) {
+            // If the process crashed during a resize, always try to relaunch it, unless it has
+            // failed more than twice. Skip activities that's already finishing cleanly by itself.
+            remove = false;
+        } else if ((!mHaveState && !stateNotNeeded
+                && !isState(ActivityState.RESTARTING_PROCESS)) || finishing) {
+            // Don't currently have state for the activity, or it is finishing -- always remove it.
+            remove = true;
+        } else if (!mVisibleRequested && launchCount > 2
+                && lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
+            // We have launched this activity too many times since it was able to run, so give up
+            // and remove it. (Note if the activity is visible, we don't remove the record. We leave
+            // the dead window on the screen but the process will not be restarted unless user
+            // explicitly tap on it.)
+            remove = true;
+        } else {
+            // The process may be gone, but the activity lives on!
+            remove = false;
+        }
+        if (remove) {
+            if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
+                Slog.i(TAG_ADD_REMOVE, "Removing activity " + this
+                        + " hasSavedState=" + mHaveState + " stateNotNeeded=" + stateNotNeeded
+                        + " finishing=" + finishing + " state=" + mState
+                        + " callers=" + Debug.getCallers(5));
+            }
+            if (!finishing || (app != null && app.isRemoved())) {
+                Slog.w(TAG, "Force removing " + this + ": app died, no saved state");
+                EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
+                        task != null ? task.mTaskId : -1, shortComponentName,
+                        "proc died without state saved");
+            }
+        } else {
+            // We have the current state for this activity, so it can be restarted later
+            // when needed.
+            if (DEBUG_APP) {
+                Slog.v(TAG_APP, "Keeping entry during removeHistory for activity " + this);
+            }
+            // Set nowVisible to previous visible state. If the app was visible while it died, we
+            // leave the dead window on screen so it's basically visible. This is needed when user
+            // later tap on the dead window, we need to stop other apps when user transfers focus
+            // to the restarted activity.
+            nowVisible = mVisibleRequested;
+        }
+        cleanUp(true /* cleanServices */, true /* setState */);
+        if (remove) {
+            removeFromHistory("appDied");
+        }
+    }
+
     @Override
     void removeImmediately() {
         onRemovedFromDisplay();
@@ -4114,6 +4179,12 @@
             // Now that the app is going invisible, we can remove it. It will be restarted
             // if made visible again.
             removeDeadWindows();
+            // If this activity is about to finish/stopped and now becomes invisible, remove it
+            // from the unknownApp list in case the activity does not want to draw anything, which
+            // keep the user waiting for the next transition to start.
+            if (finishing || isState(STOPPED)) {
+                displayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
+            }
         } else {
             if (!appTransition.isTransitionSet()
                     && appTransition.isReady()) {
@@ -5580,8 +5651,9 @@
         } else {
             // In this case another process added windows using this activity token. So, we call the
             // generic service input dispatch timed out method so that the right process is blamed.
-            return mAtmService.mAmInternal.inputDispatchingTimedOut(
-                    windowPid, false /* aboveSystem */, reason) < 0;
+            long timeoutMillis = mAtmService.mAmInternal.inputDispatchingTimedOut(
+                    windowPid, false /* aboveSystem */, reason);
+            return timeoutMillis <= 0;
         }
     }
 
@@ -7561,6 +7633,11 @@
     }
 
     @Override
+    boolean canCustomizeAppTransition() {
+        return true;
+    }
+
+    @Override
     public String toString() {
         if (stringName != null) {
             return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) +
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 04b1edc..a05289f 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -74,9 +74,9 @@
 import static com.android.server.wm.Task.ActivityState.PAUSED;
 import static com.android.server.wm.Task.ActivityState.PAUSING;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
 import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
 import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
 import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.wm.Task.TAG_CLEANUP;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
@@ -788,7 +788,7 @@
             final LockTaskController lockTaskController = mService.getLockTaskController();
             if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
                     || task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV
-                    || (task.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED
+                    || (task.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED
                             && lockTaskController.getLockTaskModeState()
                                     == LOCK_TASK_MODE_LOCKED)) {
                 lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */);
@@ -891,7 +891,7 @@
                 // This is the first time we failed -- restart process and
                 // retry.
                 r.launchFailed = true;
-                proc.removeActivity(r);
+                proc.removeActivity(r, true /* keepAssociation */);
                 throw e;
             }
         } finally {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 777ddda..2dc22ec 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -528,8 +528,8 @@
     public abstract void onActiveUidsCleared();
     public abstract void onUidProcStateChanged(int uid, int procState);
 
-    public abstract void onUidAddedToPendingTempWhitelist(int uid, String tag);
-    public abstract void onUidRemovedFromPendingTempWhitelist(int uid);
+    public abstract void onUidAddedToPendingTempAllowlist(int uid, String tag);
+    public abstract void onUidRemovedFromPendingTempAllowlist(int uid);
 
     /** Handle app crash event in {@link android.app.IActivityController} if there is one. */
     public abstract boolean handleAppCrashInActivityController(String processName, int pid,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c4af3e2..627361d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -50,6 +50,7 @@
 import static android.os.FactoryTest.FACTORY_TEST_HIGH_LEVEL;
 import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
 import static android.os.FactoryTest.FACTORY_TEST_OFF;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -182,7 +183,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -237,12 +237,9 @@
 import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.TransferPipe;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.KeyguardDismissCallback;
 import com.android.internal.util.ArrayUtils;
@@ -254,6 +251,7 @@
 import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.SystemServiceManager;
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
@@ -313,10 +311,8 @@
     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
 
-    // How long we wait until we timeout on key dispatching.
-    public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
     // How long we wait until we timeout on key dispatching during instrumentation.
-    static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+    static final long INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS = 60 * 1000;
     // How long we permit background activity starts after an activity in the process
     // started or finished.
     static final long ACTIVITY_BG_START_GRACE_PERIOD_MS = 10 * 1000;
@@ -384,7 +380,7 @@
     private AppOpsManager mAppOpsManager;
     /** All active uids in the system. */
     private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
-    private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
+    private final SparseArray<String> mPendingTempAllowlist = new SparseArray<>();
     /** All processes currently running that might have a window organized by name. */
     final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
     /** All processes we currently have running mapped by pid and uid */
@@ -1027,16 +1023,17 @@
         }
 
         @Override
-        public void onUnlockUser(int userId) {
+        public void onUserUnlocking(@NonNull TargetUser user) {
             synchronized (mService.getGlobalLock()) {
-                mService.mStackSupervisor.onUserUnlocked(userId);
+                mService.mStackSupervisor.onUserUnlocked(user.getUserIdentifier());
             }
         }
 
         @Override
-        public void onCleanupUser(int userId) {
+        public void onUserStopped(@NonNull TargetUser user) {
             synchronized (mService.getGlobalLock()) {
-                mService.mStackSupervisor.mLaunchParamsPersister.onCleanupUser(userId);
+                mService.mStackSupervisor.mLaunchParamsPersister
+                        .onCleanupUser(user.getUserIdentifier());
             }
         }
 
@@ -1109,7 +1106,7 @@
 
     @Override
     public int startActivityIntentSender(IApplicationThread caller, IIntentSender target,
-            IBinder whitelistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
+            IBinder allowlistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions) {
         enforceNotIsolatedCaller("startActivityIntentSender");
         // Refuse possible leaked file descriptors
@@ -1132,7 +1129,7 @@
                 mAppSwitchesAllowedTime = 0;
             }
         }
-        return pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
+        return pir.sendInner(0, fillInIntent, resolvedType, allowlistToken, null, null,
                 resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
     }
 
@@ -3036,7 +3033,7 @@
         // system or a specific app.
         // * System-initiated requests will only start the pinned mode (screen pinning)
         // * App-initiated requests
-        //   - will put the device in fully locked mode (LockTask), if the app is whitelisted
+        //   - will put the device in fully locked mode (LockTask), if the app is allowlisted
         //   - will start the pinned mode, otherwise
         final int callingUid = Binder.getCallingUid();
         long ident = Binder.clearCallingIdentity();
@@ -3076,7 +3073,7 @@
                     "updateLockTaskPackages()");
         }
         synchronized (mGlobalLock) {
-            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":"
+            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":"
                     + Arrays.toString(packages));
             getLockTaskController().updateLockTaskPackages(userId, packages);
         }
@@ -4094,10 +4091,6 @@
                         final Task stack = r.getRootTask();
                         stack.setPictureInPictureAspectRatio(aspectRatio);
                         stack.setPictureInPictureActions(actions);
-                        MetricsLoggerWrapper.logPictureInPictureEnter(mContext,
-                                r.info.applicationInfo.uid, r.shortComponentName,
-                                r.supportsEnterPipOnTaskSwitch);
-                        logPictureInPictureArgs(params);
                     }
                 };
 
@@ -4141,7 +4134,6 @@
                             r.pictureInPictureArgs.getAspectRatio());
                     stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
                 }
-                logPictureInPictureArgs(params);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -4155,18 +4147,6 @@
         return 3;
     }
 
-    private void logPictureInPictureArgs(PictureInPictureParams params) {
-        if (params.hasSetActions()) {
-            MetricsLogger.histogram(mContext, "tron_varz_picture_in_picture_actions_count",
-                    params.getActions().size());
-        }
-        if (params.hasSetAspectRatio()) {
-            LogMaker lm = new LogMaker(MetricsEvent.ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED);
-            lm.addTaggedData(MetricsEvent.PICTURE_IN_PICTURE_ASPECT_RATIO, params.getAspectRatio());
-            MetricsLogger.action(lm);
-        }
-    }
-
     /**
      * Checks the state of the system and the activity associated with the given {@param token} to
      * verify that picture-in-picture is supported for that activity.
@@ -5374,15 +5354,18 @@
         }
     }
 
-    static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
+    static long getInputDispatchingTimeoutMillisLocked(ActivityRecord r) {
         if (r == null || !r.hasProcess()) {
-            return KEY_DISPATCHING_TIMEOUT_MS;
+            return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         }
-        return getInputDispatchingTimeoutLocked(r.app);
+        return getInputDispatchingTimeoutMillisLocked(r.app);
     }
 
-    private static long getInputDispatchingTimeoutLocked(WindowProcessController r) {
-        return r != null ? r.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+    private static long getInputDispatchingTimeoutMillisLocked(WindowProcessController r) {
+        if (r == null) {
+            return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+        }
+        return r.getInputDispatchingTimeoutMillis();
     }
 
     /**
@@ -5975,11 +5958,11 @@
     }
 
     /**
-     * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
-     * the whitelist
+     * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
+     * the allowlist
      */
-    String getPendingTempWhitelistTagForUidLocked(int uid) {
-        return mPendingTempWhitelist.get(uid);
+    String getPendingTempAllowlistTagForUidLocked(int uid) {
+        return mPendingTempAllowlist.get(uid);
     }
 
     void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
@@ -6789,11 +6772,14 @@
         public void handleAppDied(WindowProcessController wpc, boolean restarting,
                 Runnable finishInstrumentationCallback) {
             synchronized (mGlobalLockWithoutBoost) {
-                // Remove this application's activities from active lists.
-                boolean hasVisibleActivities = mRootWindowContainer.handleAppDied(wpc);
-
-                wpc.clearRecentTasks();
-                wpc.clearActivities();
+                mStackSupervisor.beginDeferResume();
+                final boolean hasVisibleActivities;
+                try {
+                    // Remove this application's activities from active lists.
+                    hasVisibleActivities = wpc.handleAppDied();
+                } finally {
+                    mStackSupervisor.endDeferResume();
+                }
 
                 if (wpc.isInstrumenting()) {
                     finishInstrumentationCallback.run();
@@ -7318,16 +7304,16 @@
         }
 
         @Override
-        public void onUidAddedToPendingTempWhitelist(int uid, String tag) {
+        public void onUidAddedToPendingTempAllowlist(int uid, String tag) {
             synchronized (mGlobalLockWithoutBoost) {
-                mPendingTempWhitelist.put(uid, tag);
+                mPendingTempAllowlist.put(uid, tag);
             }
         }
 
         @Override
-        public void onUidRemovedFromPendingTempWhitelist(int uid) {
+        public void onUidRemovedFromPendingTempAllowlist(int uid) {
             synchronized (mGlobalLockWithoutBoost) {
-                mPendingTempWhitelist.remove(uid);
+                mPendingTempAllowlist.remove(uid);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 3abc54f..11a468b 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -203,6 +203,7 @@
     private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
 
     private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
+    private boolean mNextAppTransitionOverrideRequested;
 
     // These are the possible states for the enter/exit activities during a thumbnail transition
     private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
@@ -337,6 +338,11 @@
         mNextAppTransitionFlags |= flags;
         setLastAppTransition(TRANSIT_UNSET, null, null, null);
         updateBooster();
+        if (isTransitionSet()) {
+            removeAppTransitionTimeoutCallbacks();
+            mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable,
+                    APP_TRANSITION_TIMEOUT_MS);
+        }
     }
 
     void setLastAppTransition(int transit, ActivityRecord openingApp, ActivityRecord closingApp,
@@ -454,6 +460,7 @@
 
     void clear() {
         mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
+        mNextAppTransitionOverrideRequested = false;
         mNextAppTransitionPackage = null;
         mNextAppTransitionAnimationsSpecs.clear();
         mRemoteAnimationController = null;
@@ -1574,6 +1581,7 @@
      */
     boolean canSkipFirstFrame() {
         return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
+                && !mNextAppTransitionOverrideRequested
                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
                 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
@@ -1608,6 +1616,11 @@
             int orientation, Rect frame, Rect displayFrame, Rect insets,
             @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
             boolean freeform, WindowContainer container) {
+
+        if (mNextAppTransitionOverrideRequested && container.canCustomizeAppTransition()) {
+            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
+        }
+
         Animation a;
         if (isKeyguardGoingAwayTransit(transit) && enter) {
             a = loadKeyguardExitAnimation(transit);
@@ -1648,7 +1661,6 @@
                     "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
                             + "isEntrance=%b Callers=%s",
                     a, appTransitionToString(transit), enter, Debug.getCallers(3));
-            setAppTransitionFinishedCallbackIfNeeded(a);
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
             a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
@@ -1775,6 +1787,7 @@
                     a, animAttr, appTransitionToString(transit), enter,
                     Debug.getCallers(3));
         }
+        setAppTransitionFinishedCallbackIfNeeded(a);
         return a;
     }
 
@@ -1816,7 +1829,7 @@
             IRemoteCallback startedCallback, IRemoteCallback endedCallback) {
         if (canOverridePendingAppTransition()) {
             clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
+            mNextAppTransitionOverrideRequested = true;
             mNextAppTransitionPackage = packageName;
             mNextAppTransitionEnter = enterAnim;
             mNextAppTransitionExit = exitAnim;
@@ -2134,15 +2147,16 @@
             pw.print(prefix); pw.print("mNextAppTransitionType=");
                     pw.println(transitTypeToString());
         }
+        if (mNextAppTransitionOverrideRequested
+                || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
+            pw.print(prefix); pw.print("mNextAppTransitionPackage=");
+            pw.println(mNextAppTransitionPackage);
+            pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
+            pw.print(Integer.toHexString(mNextAppTransitionEnter));
+            pw.print(" mNextAppTransitionExit=0x");
+            pw.println(Integer.toHexString(mNextAppTransitionExit));
+        }
         switch (mNextAppTransitionType) {
-            case NEXT_TRANSIT_TYPE_CUSTOM:
-                pw.print(prefix); pw.print("mNextAppTransitionPackage=");
-                        pw.println(mNextAppTransitionPackage);
-                pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
-                        pw.print(Integer.toHexString(mNextAppTransitionEnter));
-                        pw.print(" mNextAppTransitionExit=0x");
-                        pw.println(Integer.toHexString(mNextAppTransitionExit));
-                break;
             case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
                 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
                         pw.println(mNextAppTransitionPackage);
@@ -2229,12 +2243,7 @@
                 setAppTransition(transit, flags);
             }
         }
-        boolean prepared = prepare();
-        if (isTransitionSet()) {
-            removeAppTransitionTimeoutCallbacks();
-            mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable, APP_TRANSITION_TIMEOUT_MS);
-        }
-        return prepared;
+        return prepare();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index f840d92..22dd1d3 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
 import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
 import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
 import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
@@ -271,8 +273,7 @@
 
             mDragApplicationHandle = new InputApplicationHandle(new Binder());
             mDragApplicationHandle.name = "drag";
-            mDragApplicationHandle.dispatchingTimeoutNanos =
-                    WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+            mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 
             mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
                     display.getDisplayId());
@@ -280,8 +281,7 @@
             mDragWindowHandle.token = mServerChannel.getToken();
             mDragWindowHandle.layoutParamsFlags = 0;
             mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
-            mDragWindowHandle.dispatchingTimeoutNanos =
-                    WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+            mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
             mDragWindowHandle.visible = true;
             mDragWindowHandle.canReceiveKeys = false;
             mDragWindowHandle.hasFocus = true;
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 852b3672..3b24584b 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -69,16 +71,14 @@
 
         mApplicationHandle = new InputApplicationHandle(new Binder());
         mApplicationHandle.name = name;
-        mApplicationHandle.dispatchingTimeoutNanos =
-                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        mApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 
         mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
         mWindowHandle.name = name;
         mWindowHandle.token = mServerChannel.getToken();
         mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
         mWindowHandle.layoutParamsFlags = 0;
-        mWindowHandle.dispatchingTimeoutNanos =
-                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         mWindowHandle.visible = true;
         mWindowHandle.canReceiveKeys = false;
         mWindowHandle.hasFocus = false;
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 9c4ac89..e166bfc 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -10,6 +10,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS;
 
+import android.annotation.Nullable;
 import android.os.Build;
 import android.os.Debug;
 import android.os.IBinder;
@@ -173,23 +174,23 @@
      */
     @Override
     public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
-            String reason) {
+            @Nullable Integer pid, String reason) {
         final long startTime = SystemClock.uptimeMillis();
         try {
-            return notifyANRInner(inputApplicationHandle, token, reason);
+            return notifyANRInner(inputApplicationHandle, token, pid, reason);
         } finally {
             // Log the time because the method is called from InputDispatcher thread. It shouldn't
-            // take too long that may affect input response time.
+            // take too long because it blocks input while executing.
             Slog.d(TAG_WM, "notifyANR took " + (SystemClock.uptimeMillis() - startTime) + "ms");
         }
     }
 
     private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token,
-            String reason) {
+            @Nullable Integer pid, String reason) {
         ActivityRecord activity = null;
         WindowState windowState = null;
         boolean aboveSystem = false;
-        int windowPid = INVALID_PID;
+        int windowPid = pid != null ? pid : INVALID_PID;
 
         preDumpIfLockTooSlow();
 
@@ -258,18 +259,14 @@
             if (!abort) {
                 // The activity manager declined to abort dispatching.
                 // Wait a bit longer and timeout again later.
-                return activity.mInputDispatchingTimeoutNanos;
+                return TimeUnit.MILLISECONDS.toNanos(activity.mInputDispatchingTimeoutMillis);
             }
         } else if (windowState != null || windowPid != INVALID_PID) {
             // Notify the activity manager about the timeout and let it decide whether
             // to abort dispatching or keep waiting.
-            long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem,
-                    reason);
-            if (timeout >= 0) {
-                // The activity manager declined to abort dispatching.
-                // Wait a bit longer and timeout again later.
-                return timeout * 1000000L; // nanoseconds
-            }
+            long timeoutMillis =
+                    mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem, reason);
+            return TimeUnit.MILLISECONDS.toNanos(timeoutMillis);
         }
         return 0; // abort dispatching
     }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 20f1b9f..791f471 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -269,7 +269,7 @@
         flags = child.getSurfaceTouchableRegion(inputWindowHandle, flags);
         inputWindowHandle.layoutParamsFlags = flags;
         inputWindowHandle.layoutParamsType = type;
-        inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
+        inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
         inputWindowHandle.visible = isVisible;
         inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
         inputWindowHandle.hasFocus = hasFocus;
@@ -385,7 +385,7 @@
         } else {
             final InputApplicationHandle handle = newApp.mInputApplicationHandle;
             handle.name = newApp.toString();
-            handle.dispatchingTimeoutNanos = newApp.mInputDispatchingTimeoutNanos;
+            handle.dispatchingTimeoutMillis = newApp.mInputDispatchingTimeoutMillis;
 
             mService.mInputManager.setFocusedApplication(mDisplayId, handle);
         }
@@ -570,8 +570,7 @@
             final String name, final int type, final boolean isVisible) {
         inputWindowHandle.name = name;
         inputWindowHandle.layoutParamsType = type;
-        inputWindowHandle.dispatchingTimeoutNanos =
-                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
         inputWindowHandle.visible = isVisible;
         inputWindowHandle.canReceiveKeys = false;
         inputWindowHandle.hasFocus = false;
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 28dcbcd..dccd3a6 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.view.SurfaceControl.HIDDEN;
 
 import android.graphics.Point;
@@ -217,8 +218,7 @@
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                     | WindowManager.LayoutParams.FLAG_SLIPPERY;
             mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
-            mWindowHandle.dispatchingTimeoutNanos =
-                    WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+            mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
             mWindowHandle.visible = true;
             mWindowHandle.ownerPid = Process.myPid();
             mWindowHandle.ownerUid = Process.myUid();
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index c7a438d..8ef57f7 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -33,11 +33,11 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
 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.Task.LOCK_TASK_AUTH_ALLOWLISTED;
 import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
 import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -264,12 +264,12 @@
     }
 
     /**
-     * @return whether the requested task is allowed to be locked (either whitelisted, or declares
+     * @return whether the requested task is allowed to be locked (either allowlisted, or declares
      * lockTaskMode="always" in the manifest).
      */
-    boolean isTaskWhitelisted(Task task) {
+    boolean isTaskAllowlisted(Task task) {
         switch(task.mLockTaskAuth) {
-            case LOCK_TASK_AUTH_WHITELISTED:
+            case LOCK_TASK_AUTH_ALLOWLISTED:
             case LOCK_TASK_AUTH_LAUNCHABLE:
             case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
                 return true;
@@ -311,7 +311,7 @@
 
     private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
         // TODO: Double check what's going on here. If the task is already in lock task mode, it's
-        // likely whitelisted, so will return false below.
+        // likely allowlisted, so will return false below.
         if (isTaskLocked(task) && !isNewClearTask) {
             // If the task is already at the top and won't be cleared, then allow the operation
             return false;
@@ -327,7 +327,7 @@
             return false;
         }
 
-        return !(isTaskWhitelisted(task) || mLockTaskModeTasks.isEmpty());
+        return !(isTaskAllowlisted(task) || mLockTaskModeTasks.isEmpty());
     }
 
     private boolean isRecentsAllowed(int userId) {
@@ -356,7 +356,7 @@
                 return false;
             default:
         }
-        return isPackageWhitelisted(userId, packageName);
+        return isPackageAllowlisted(userId, packageName);
     }
 
     private boolean isEmergencyCallTask(Task task) {
@@ -556,7 +556,7 @@
         if (!isSystemCaller) {
             task.mLockTaskUid = callingUid;
             if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
-                // startLockTask() called by app, but app is not part of lock task whitelist. Show
+                // startLockTask() called by app, but app is not part of lock task allowlist. Show
                 // app pinning request. We will come back here with isSystemCaller true.
                 if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
                 StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -649,8 +649,8 @@
 
     /**
      * Update packages that are allowed to be launched in lock task mode.
-     * @param userId Which user this whitelist is associated with
-     * @param packages The whitelist of packages allowed in lock task mode
+     * @param userId Which user this allowlist is associated with
+     * @param packages The allowlist of packages allowed in lock task mode
      * @see #mLockTaskPackages
      */
     void updateLockTaskPackages(int userId, String[] packages) {
@@ -659,19 +659,19 @@
         boolean taskChanged = false;
         for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final Task lockedTask = mLockTaskModeTasks.get(taskNdx);
-            final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
-                    || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+            final boolean wasAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+                    || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
             lockedTask.setLockTaskAuth();
-            final boolean isWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
-                    || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+            final boolean isAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+                    || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
 
             if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
                     || lockedTask.mUserId != userId
-                    || !wasWhitelisted || isWhitelisted) {
+                    || !wasAllowlisted || isAllowlisted) {
                 continue;
             }
 
-            // Terminate locked tasks that have recently lost whitelist authorization.
+            // Terminate locked tasks that have recently lost allowlist authorization.
             if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
                     lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
             removeLockedTask(lockedTask);
@@ -697,17 +697,17 @@
         }
     }
 
-    boolean isPackageWhitelisted(int userId, String pkg) {
+    boolean isPackageAllowlisted(int userId, String pkg) {
         if (pkg == null) {
             return false;
         }
-        String[] whitelist;
-        whitelist = mLockTaskPackages.get(userId);
-        if (whitelist == null) {
+        String[] allowlist;
+        allowlist = mLockTaskPackages.get(userId);
+        if (allowlist == null) {
             return false;
         }
-        for (String whitelistedPkg : whitelist) {
-            if (pkg.equals(whitelistedPkg)) {
+        for (String allowlistedPkg : allowlist) {
+            if (pkg.equals(allowlistedPkg)) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
index 0f92bc8..61b6e0b 100644
--- a/services/core/java/com/android/server/wm/PolicyControl.java
+++ b/services/core/java/com/android/server/wm/PolicyControl.java
@@ -196,40 +196,40 @@
         private static final String ALL = "*";
         private static final String APPS = "apps";
 
-        private final ArraySet<String> mWhitelist;
-        private final ArraySet<String> mBlacklist;
+        private final ArraySet<String> mAllowlist;
+        private final ArraySet<String> mDenylist;
 
-        private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
-            mWhitelist = whitelist;
-            mBlacklist = blacklist;
+        private Filter(ArraySet<String> allowlist, ArraySet<String> denylist) {
+            mAllowlist = allowlist;
+            mDenylist = denylist;
         }
 
         boolean matches(LayoutParams attrs) {
             if (attrs == null) return false;
             boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                     && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-            if (isApp && mBlacklist.contains(APPS)) return false;
-            if (onBlacklist(attrs.packageName)) return false;
-            if (isApp && mWhitelist.contains(APPS)) return true;
-            return onWhitelist(attrs.packageName);
+            if (isApp && mDenylist.contains(APPS)) return false;
+            if (onDenylist(attrs.packageName)) return false;
+            if (isApp && mAllowlist.contains(APPS)) return true;
+            return onAllowlist(attrs.packageName);
         }
 
         boolean matches(String packageName) {
-            return !onBlacklist(packageName) && onWhitelist(packageName);
+            return !onDenylist(packageName) && onAllowlist(packageName);
         }
 
-        private boolean onBlacklist(String packageName) {
-            return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+        private boolean onDenylist(String packageName) {
+            return mDenylist.contains(packageName) || mDenylist.contains(ALL);
         }
 
-        private boolean onWhitelist(String packageName) {
-            return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+        private boolean onAllowlist(String packageName) {
+            return mAllowlist.contains(ALL) || mAllowlist.contains(packageName);
         }
 
         void dump(PrintWriter pw) {
             pw.print("Filter[");
-            dump("whitelist", mWhitelist, pw); pw.print(',');
-            dump("blacklist", mBlacklist, pw); pw.print(']');
+            dump("allowlist", mAllowlist, pw); pw.print(',');
+            dump("denylist", mDenylist, pw); pw.print(']');
         }
 
         private void dump(String name, ArraySet<String> set, PrintWriter pw) {
@@ -253,18 +253,18 @@
         // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
         static Filter parse(String value) {
             if (value == null) return null;
-            ArraySet<String> whitelist = new ArraySet<String>();
-            ArraySet<String> blacklist = new ArraySet<String>();
+            ArraySet<String> allowlist = new ArraySet<String>();
+            ArraySet<String> denylist = new ArraySet<String>();
             for (String token : value.split(",")) {
                 token = token.trim();
                 if (token.startsWith("-") && token.length() > 1) {
                     token = token.substring(1);
-                    blacklist.add(token);
+                    denylist.add(token);
                 } else {
-                    whitelist.add(token);
+                    allowlist.add(token);
                 }
             }
-            return new Filter(whitelist, blacklist);
+            return new Filter(allowlist, denylist);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index ba2c0b6..df53563 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -655,7 +655,8 @@
         }
         for (int i = mTasks.size() - 1; i >= 0; --i) {
             final Task task = mTasks.get(i);
-            if (task.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(task)) {
+            if (task.mUserId == userId
+                    && !mService.getLockTaskController().isTaskAllowlisted(task)) {
                 remove(task);
             }
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 06dec7c..1cb483c 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2155,6 +2155,7 @@
                 // non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
                 // to its previous freeform bounds.
                 stack.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds);
+                stack.setBounds(task.getBounds());
 
                 // There are multiple activities in the task and moving the top activity should
                 // reveal/leave the other activities in their original task.
@@ -2570,7 +2571,7 @@
         mDisplayAccessUIDs.clear();
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             final DisplayContent displayContent = getChildAt(displayNdx);
-            // Only bother calculating the whitelist for private displays
+            // Only bother calculating the allowlist for private displays
             if (displayContent.isPrivate()) {
                 mDisplayAccessUIDs.append(
                         displayContent.mDisplayId, displayContent.getPresentUIDs());
@@ -2751,7 +2752,7 @@
         if (r.app != app) return;
         Slog.w(TAG, "  Force finishing activity "
                 + r.intent.getComponent().flattenToShortString());
-        r.app = null;
+        r.detachFromProcess();
         r.getDisplay().mDisplayContent.prepareAppTransition(
                 TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
         r.destroyIfPossible("handleAppCrashed");
@@ -3104,22 +3105,6 @@
         return null;
     }
 
-    boolean handleAppDied(WindowProcessController app) {
-        if (app.isRemoved()) {
-            // The package of the died process should be force-stopped, so make its activities as
-            // finishing to prevent the process from being started again if the next top (or being
-            // visible) activity also resides in the same process.
-            app.makeFinishingForProcessRemoved();
-        }
-        return reduceOnAllTaskDisplayAreas((taskDisplayArea, result) -> {
-            for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
-                final Task stack = taskDisplayArea.getStackAt(sNdx);
-                result |= stack.handleAppDied(app);
-            }
-            return result;
-        }, false /* initValue */);
-    }
-
     void closeSystemDialogActivities(String reason) {
         forAllActivities((r) -> {
             if ((r.info.flags & ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index b71ecbb..ede6708 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -233,10 +233,10 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        // Check if someone tries to launch an unwhitelisted activity into LockTask mode.
+        // Check if someone tries to launch an unallowlisted activity into LockTask mode.
         final boolean lockTaskMode = options.getLockTaskMode();
         if (aInfo != null && lockTaskMode
-                && !supervisor.mService.getLockTaskController().isPackageWhitelisted(
+                && !supervisor.mService.getLockTaskController().isPackageAllowlisted(
                         UserHandle.getUserId(callingUid), aInfo.packageName)) {
             final String msg = "Permission Denial: starting " + getIntentString(intent)
                     + " from " + callerApp + " (pid=" + callingPid
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 897b680..be0815b0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -45,7 +45,7 @@
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -86,8 +86,6 @@
 import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
 import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
@@ -115,8 +113,6 @@
 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.H.FIRST_ACTIVITY_STACK_MSG;
-import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
-import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -214,7 +210,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledFunction;
@@ -415,7 +410,7 @@
     /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
     final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
     /** Can enter lockTask without user approval. Can start over existing lockTask task. */
-    final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+    final static int LOCK_TASK_AUTH_ALLOWLISTED = 3;
     /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
      * lockTask task. */
     final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
@@ -746,111 +741,6 @@
         }
     }
 
-    // TODO: Can we just loop through WindowProcessController#mActivities instead of doing this?
-    private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp =
-            new RemoveHistoryRecordsForApp();
-    private class RemoveHistoryRecordsForApp {
-        private boolean mHasVisibleActivities;
-        private boolean mIsProcessRemoved;
-        private WindowProcessController mApp;
-        private ArrayList<ActivityRecord> mToRemove = new ArrayList<>();
-
-        boolean process(WindowProcessController app) {
-            mToRemove.clear();
-            mHasVisibleActivities = false;
-            mApp = app;
-            mIsProcessRemoved = app.isRemoved();
-
-            final PooledConsumer c = PooledLambda.obtainConsumer(
-                    RemoveHistoryRecordsForApp::addActivityToRemove, this,
-                    PooledLambda.__(ActivityRecord.class));
-            forAllActivities(c);
-            c.recycle();
-
-            while (!mToRemove.isEmpty()) {
-                processActivity(mToRemove.remove(0));
-            }
-
-            mApp = null;
-            return mHasVisibleActivities;
-        }
-
-        private void addActivityToRemove(ActivityRecord r) {
-            if (r.app == mApp) {
-                mToRemove.add(r);
-            }
-        }
-
-        private void processActivity(ActivityRecord r) {
-            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record " + r + ": app=" + r.app);
-
-            if (r.app != mApp) {
-                return;
-            }
-            if (r.isVisible() || r.mVisibleRequested) {
-                // While an activity launches a new activity, it's possible that the old
-                // activity is already requested to be hidden (mVisibleRequested=false), but
-                // this visibility is not yet committed, so isVisible()=true.
-                mHasVisibleActivities = true;
-            }
-            final boolean remove;
-            if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
-                    || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
-                    && r.launchCount < 3 && !r.finishing) {
-                // If the process crashed during a resize, always try to relaunch it, unless
-                // it has failed more than twice. Skip activities that's already finishing
-                // cleanly by itself.
-                remove = false;
-            } else if ((!r.hasSavedState() && !r.stateNotNeeded
-                    && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) {
-                // Don't currently have state for the activity, or
-                // it is finishing -- always remove it.
-                remove = true;
-            } else if (!r.mVisibleRequested && r.launchCount > 2
-                    && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
-                // We have launched this activity too many times since it was
-                // able to run, so give up and remove it.
-                // (Note if the activity is visible, we don't remove the record.
-                // We leave the dead window on the screen but the process will
-                // not be restarted unless user explicitly tap on it.)
-                remove = true;
-            } else {
-                // The process may be gone, but the activity lives on!
-                remove = false;
-            }
-            if (remove) {
-                if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
-                        "Removing activity " + r + " from stack "
-                                + ": hasSavedState=" + r.hasSavedState()
-                                + " stateNotNeeded=" + r.stateNotNeeded
-                                + " finishing=" + r.finishing
-                                + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
-                if (!r.finishing || mIsProcessRemoved) {
-                    Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
-                    EventLogTags.writeWmFinishActivity(r.mUserId,
-                            System.identityHashCode(r), r.getTask().mTaskId,
-                            r.shortComponentName, "proc died without state saved");
-                }
-            } else {
-                // We have the current state for this activity, so
-                // it can be restarted later when needed.
-                if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null");
-                if (DEBUG_APP) Slog.v(TAG_APP,
-                        "Clearing app during removeHistory for activity " + r);
-                r.app = null;
-                // Set nowVisible to previous visible state. If the app was visible while
-                // it died, we leave the dead window on screen so it's basically visible.
-                // This is needed when user later tap on the dead window, we need to stop
-                // other apps when user transfers focus to the restarted activity.
-                r.nowVisible = r.mVisibleRequested;
-            }
-            r.cleanUp(true /* cleanServices */, true /* setState */);
-            if (remove) {
-                r.removeFromHistory("appDied");
-            }
-        }
-    }
-
     private final FindRootHelper mFindRootHelper = new FindRootHelper();
     private class FindRootHelper {
         private ActivityRecord mRoot;
@@ -1795,7 +1685,7 @@
             getDisplayArea().addStackReferenceIfNeeded((Task) child);
         }
 
-        // Make sure the list of display UID whitelists is updated
+        // Make sure the list of display UID allowlists is updated
         // now that this record is in a new task.
         mRootWindowContainer.updateUIDsPresentOnDisplay();
 
@@ -2012,7 +1902,7 @@
             case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
             case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
             case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
-            case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+            case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED";
             case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
             default: return "unknown=" + mLockTaskAuth;
         }
@@ -2032,8 +1922,8 @@
         final LockTaskController lockTaskController = mAtmService.getLockTaskController();
         switch (r.lockTaskLaunchMode) {
             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
-                mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
-                        ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+                mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
+                        ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_NEVER:
@@ -2044,8 +1934,8 @@
                 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
                 break;
 
-            case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
-                mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+            case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+                mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
                         ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
                 break;
         }
@@ -2475,7 +2365,6 @@
     private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
         if (mWmService.mDisableTransitionAnimation
                 || !isVisible()
-                || getDisplayContent().mAppTransition.isTransitionSet()
                 || getSurfaceControl() == null
                 || !isLeafTask()) {
             return false;
@@ -7167,9 +7056,8 @@
     /**
      * Reset local parameters because an app's activity died.
      * @param app The app of the activity that died.
-     * @return result from removeHistoryRecordsForAppLocked.
      */
-    boolean handleAppDied(WindowProcessController app) {
+    void handleAppDied(WindowProcessController app) {
         if (mPausingActivity != null && mPausingActivity.app == app) {
             if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
                     "App died while pausing: " + mPausingActivity);
@@ -7179,9 +7067,6 @@
             mLastPausedActivity = null;
             mLastNoHistoryActivity = null;
         }
-
-        mStackSupervisor.removeHistoryRecords(app);
-        return mRemoveHistoryRecordsForApp.process(app);
     }
 
     boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
@@ -7485,8 +7370,6 @@
             getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
 
             mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
-            MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext,
-                    task.effectiveUid, task.realActivity.flattenToString());
         });
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index c68b660..3fbc037 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
@@ -230,8 +231,8 @@
 
         mDragApplicationHandle = new InputApplicationHandle(new Binder());
         mDragApplicationHandle.name = TAG;
-        mDragApplicationHandle.dispatchingTimeoutNanos =
-                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
 
         mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
                 displayContent.getDisplayId());
@@ -239,8 +240,7 @@
         mDragWindowHandle.token = mServerChannel.getToken();
         mDragWindowHandle.layoutParamsFlags = 0;
         mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
-        mDragWindowHandle.dispatchingTimeoutNanos =
-                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         mDragWindowHandle.visible = true;
         mDragWindowHandle.canReceiveKeys = false;
         mDragWindowHandle.hasFocus = true;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a3a4e40..e24d185 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -857,6 +857,14 @@
     }
 
     /**
+     * @return {@code true} when an application can override an app transition animation on this
+     * container.
+     */
+    boolean canCustomizeAppTransition() {
+        return !WindowManagerService.sDisableCustomTaskAnimationProperty;
+    }
+
+    /**
      * @return {@code true} when this container or its related containers are running an
      * animation, {@code false} otherwise.
      *
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9acaa9e..0b1d6bc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -35,6 +35,7 @@
 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
 import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.myPid;
@@ -366,9 +367,6 @@
     // proceding with safe mode detection.
     private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000;
 
-    // Default input dispatching timeout in nanoseconds.
-    static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
-
     // Poll interval in milliseconds for watching boot animation finished.
     // TODO(b/159045990) Migrate to SystemService.waitForState with dedicated thread.
     private static final int BOOT_ANIMATION_POLL_INTERVAL = 50;
@@ -395,6 +393,21 @@
     // trying to apply a new one.
     private static final boolean ALWAYS_KEEP_CURRENT = true;
 
+    /**
+     * Restrict ability of activities overriding transition animation in a way such that
+     * an activity can do it only when the transition happens within a same task.
+     *
+     * @see android.app.Activity#overridePendingTransition(int, int)
+     */
+    private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
+            "persist.wm.disable_custom_task_animation";
+
+    /**
+     * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
+     */
+    static boolean sDisableCustomTaskAnimationProperty =
+            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, false);
+
     private static final String DISABLE_TRIPLE_BUFFERING_PROPERTY =
             "ro.sf.disable_triple_buffer";
 
@@ -8075,7 +8088,7 @@
                 | LayoutParams.FLAG_SLIPPERY);
         h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
         h.layoutParamsType = type;
-        h.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         h.canReceiveKeys = false;
         h.hasFocus = false;
         h.hasWallpaper = false;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 6ba8769..a58c564 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.os.Build.VERSION_CODES.Q;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -30,8 +31,7 @@
 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.ACTIVITY_BG_START_GRACE_PERIOD_MS;
-import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
-import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.Task.ActivityState.DESTROYED;
 import static com.android.server.wm.Task.ActivityState.DESTROYING;
@@ -41,6 +41,7 @@
 import static com.android.server.wm.Task.ActivityState.STARTED;
 import static com.android.server.wm.Task.ActivityState.STOPPING;
 
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -177,8 +178,10 @@
     // Whether this process has ever started a service with the BIND_INPUT_METHOD permission.
     private volatile boolean mHasImeService;
 
-    // all activities running in the process
+    /** All activities running in the process (exclude destroying). */
     private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
+    /** The activities will be removed but still belong to this process. */
+    private ArrayList<ActivityRecord> mInactiveActivities;
     // any tasks this process had run root activities in
     private final ArrayList<Task> mRecentTasks = new ArrayList<>();
     // The most recent top-most activity that was resumed in the process for pre-Q app.
@@ -635,21 +638,39 @@
             return;
         }
         mActivities.add(r);
+        if (mInactiveActivities != null) {
+            mInactiveActivities.remove(r);
+        }
         updateActivityConfigurationListener();
     }
 
-    void removeActivity(ActivityRecord r) {
+    /**
+     * Indicates that the given activity is no longer active in this process.
+     *
+     * @param r The running activity to be removed.
+     * @param keepAssociation {@code true} if the activity still belongs to this process but will
+     *                        be removed soon, e.g. destroying. From the perspective of process
+     *                        priority, the process is not important if it only contains activities
+     *                        that are being destroyed. But the association is still needed to
+     *                        ensure all activities are reachable from this process.
+     */
+    void removeActivity(ActivityRecord r, boolean keepAssociation) {
+        if (keepAssociation) {
+            if (mInactiveActivities == null) {
+                mInactiveActivities = new ArrayList<>();
+                mInactiveActivities.add(r);
+            } else if (!mInactiveActivities.contains(r)) {
+                mInactiveActivities.add(r);
+            }
+        } else if (mInactiveActivities != null) {
+            mInactiveActivities.remove(r);
+        }
         mActivities.remove(r);
         updateActivityConfigurationListener();
     }
 
-    void makeFinishingForProcessRemoved() {
-        for (int i = mActivities.size() - 1; i >= 0; --i) {
-            mActivities.get(i).makeFinishingLocked();
-        }
-    }
-
     void clearActivities() {
+        mInactiveActivities = null;
         mActivities.clear();
         updateActivityConfigurationListener();
     }
@@ -1044,10 +1065,16 @@
         return RELAUNCH_REASON_NONE;
     }
 
-    public long getInputDispatchingTimeout() {
+    /**
+     * Get the current dispatching timeout. If instrumentation is currently taking place, return
+     * a longer value. Shorter timeout is returned otherwise.
+     * @return The timeout in milliseconds
+     */
+    public long getInputDispatchingTimeoutMillis() {
         synchronized (mAtm.mGlobalLock) {
             return isInstrumenting() || isUsingWrapper()
-                    ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS : KEY_DISPATCHING_TIMEOUT_MS;
+                    ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS :
+                    DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
         }
     }
 
@@ -1142,6 +1169,47 @@
         mAtm.mH.sendMessage(m);
     }
 
+    /**
+     * Clean up the activities belonging to this process.
+     *
+     * @return {@code true} if the process has any visible activity.
+     */
+    boolean handleAppDied() {
+        mAtm.mStackSupervisor.removeHistoryRecords(this);
+
+        final boolean isRemoved = isRemoved();
+        boolean hasVisibleActivities = false;
+        if (mInactiveActivities != null && !mInactiveActivities.isEmpty()) {
+            // Make sure that all activities in this process are handled.
+            mActivities.addAll(mInactiveActivities);
+        }
+        for (int i = mActivities.size() - 1; i >= 0; i--) {
+            final ActivityRecord r = mActivities.get(i);
+            if (r.mVisibleRequested || r.isVisible()) {
+                // While an activity launches a new activity, it's possible that the old activity
+                // is already requested to be hidden (mVisibleRequested=false), but this visibility
+                // is not yet committed, so isVisible()=true.
+                hasVisibleActivities = true;
+            }
+            if (isRemoved) {
+                // The package of the died process should be force-stopped, so make its activities
+                // as finishing to prevent the process from being started again if the next top (or
+                // being visible) activity also resides in the same process.
+                r.makeFinishingLocked();
+            }
+
+            final Task rootTask = r.getRootTask();
+            if (rootTask != null) {
+                rootTask.handleAppDied(this);
+            }
+            r.handleAppDied();
+        }
+        clearRecentTasks();
+        clearActivities();
+
+        return hasVisibleActivities;
+    }
+
     void registerDisplayConfigurationListener(DisplayContent displayContent) {
         if (displayContent == null) {
             return;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ef78420..ab78e74 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -25,6 +25,7 @@
 import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.graphics.GraphicsProtos.dumpPointProto;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.InsetsState.ITYPE_IME;
@@ -1635,10 +1636,10 @@
         }
     }
 
-    public long getInputDispatchingTimeoutNanos() {
+    public long getInputDispatchingTimeoutMillis() {
         return mActivityRecord != null
-                ? mActivityRecord.mInputDispatchingTimeoutNanos
-                : WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+                ? mActivityRecord.mInputDispatchingTimeoutMillis
+                : DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
     }
 
     @Override
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 0e1b2f2..4b5f38c 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -99,6 +99,7 @@
         "libpowermanager",
         "libutils",
         "libui",
+        "libvibratorservice",
         "libinput",
         "libinputflinger",
         "libinputflinger_base",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 05aa359..74e2328 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -33,6 +33,8 @@
 #include <inttypes.h>
 #include <stdio.h>
 
+#include <vibratorservice/VibratorHalController.h>
+
 using android::hardware::Return;
 using android::hardware::Void;
 using android::hardware::vibrator::V1_0::EffectStrength;
@@ -226,8 +228,24 @@
     return val >= *iter.begin() && val <= *std::prev(iter.end());
 }
 
-static void vibratorInit(JNIEnv *env, jclass clazz)
-{
+static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
+    aidl::CompositeEffect effect;
+    effect.primitive = static_cast<aidl::CompositePrimitive>(
+            env->GetIntField(primitive, gPrimitiveClassInfo.id));
+    effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale));
+    effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
+    return effect;
+}
+
+static void destroyVibratorController(void* rawVibratorController) {
+    vibrator::HalController* vibratorController =
+            reinterpret_cast<vibrator::HalController*>(rawVibratorController);
+    if (vibratorController) {
+        delete vibratorController;
+    }
+}
+
+static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) {
     if (auto hal = getHal<aidl::IVibrator>()) {
         // IBinder::pingBinder isn't accessible as a pointer function
         // but getCapabilities can serve the same purpose
@@ -236,25 +254,26 @@
     } else {
         halCall(&V1_0::IVibrator::ping).isOk();
     }
+    std::unique_ptr<vibrator::HalController> controller =
+            std::make_unique<vibrator::HalController>();
+    controller->init();
+    return reinterpret_cast<jlong>(controller.release());
 }
 
-static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */)
-{
-    bool ok;
+static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController));
+}
 
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        // IBinder::pingBinder isn't accessible as a pointer function
-        // but getCapabilities can serve the same purpose
-        int32_t cap;
-        ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
-    } else {
-        ok = halCall(&V1_0::IVibrator::ping).isOk();
+static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorExists failed because controller was not initialized");
+        return JNI_FALSE;
     }
-    return ok ? JNI_TRUE : JNI_FALSE;
+    return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE;
 }
 
-static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
-{
+static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) {
     if (auto hal = getHal<aidl::IVibrator>()) {
         auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr);
         if (!status.isOk()) {
@@ -268,93 +287,53 @@
     }
 }
 
-static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */)
-{
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        auto status = hal->call(&aidl::IVibrator::off);
-        if (!status.isOk()) {
-            ALOGE("vibratorOff command failed: %s", status.toString8().string());
-        }
-    } else {
-        Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
-        if (retStatus != Status::OK) {
-            ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
-        }
+static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorOff failed because controller was not initialized");
+        return;
     }
+    controller->off();
 }
 
-static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) {
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        int32_t cap = 0;
-        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
-            return false;
-        }
-        return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
-    } else {
-        return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
+static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+                                 jint amplitude) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorSetAmplitude failed because controller was not initialized");
+        return;
     }
+    controller->setAmplitude(static_cast<int32_t>(amplitude));
 }
 
-static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) {
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, static_cast<float>(amplitude) / UINT8_MAX);
-        if (!status.isOk()) {
-            ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string());
-        }
-    } else {
-        Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
-            .withDefault(Status::UNKNOWN_ERROR);
-        if (status != Status::OK) {
-            ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
-                  static_cast<uint32_t>(status));
-        }
+static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+                                       jboolean enabled) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorSetExternalControl failed because controller was not initialized");
+        return;
     }
+    controller->setExternalControl(enabled);
 }
 
-static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) {
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        int32_t cap = 0;
-        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
-            return false;
-        }
-        return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
-    } else {
-        return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
-    }
-}
-
-static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) {
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled);
-        if (!status.isOk()) {
-            ALOGE("Failed to set vibrator external control: %s", status.toString8().string());
-        }
-    } else {
-        Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
-            .withDefault(Status::UNKNOWN_ERROR);
-        if (status != Status::OK) {
-            ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
-                static_cast<uint32_t>(status));
-        }
-    }
-}
-
-static jintArray vibratorGetSupportedEffects(JNIEnv *env, jclass) {
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        std::vector<aidl::Effect> supportedEffects;
-        if (!hal->call(&aidl::IVibrator::getSupportedEffects, &supportedEffects).isOk()) {
-            return nullptr;
-        }
-        jintArray arr = env->NewIntArray(supportedEffects.size());
-        env->SetIntArrayRegion(arr, 0, supportedEffects.size(),
-                reinterpret_cast<jint*>(supportedEffects.data()));
-        return arr;
-    } else {
+static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorGetSupportedEffects failed because controller was not initialized");
         return nullptr;
     }
+    auto result = 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 jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
+static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong effect, jlong strength,
                                    jobject vibration, jboolean withCallback) {
     if (auto hal = getHal<aidl::IVibrator>()) {
         int32_t lengthMs;
@@ -420,17 +399,8 @@
     return -1;
 }
 
-static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
-    aidl::CompositeEffect effect;
-    effect.primitive = static_cast<aidl::CompositePrimitive>(
-            env->GetIntField(primitive, gPrimitiveClassInfo.id));
-    effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale));
-    effect.delayMs = static_cast<int>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
-    return effect;
-}
-
-static void vibratorPerformComposedEffect(JNIEnv* env, jclass, jobjectArray composition,
-                                   jobject vibration) {
+static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jobjectArray composition,
+                                          jobject vibration) {
     auto hal = getHal<aidl::IVibrator>();
     if (!hal) {
         return;
@@ -451,65 +421,71 @@
     }
 }
 
-static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
-    if (auto hal = getHal<aidl::IVibrator>()) {
-        int32_t cap = 0;
-        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
-            return 0;
-        }
-        return cap;
+static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorGetCapabilities failed because controller was not initialized");
+        return 0;
     }
-
-    return 0;
+    auto result = controller->getCapabilities();
+    return result.isOk() ? static_cast<jlong>(result.value()) : 0;
 }
 
-static void vibratorAlwaysOnEnable(JNIEnv* env, jclass, jlong id, jlong effect, jlong strength) {
-    auto status = halCall(&aidl::IVibrator::alwaysOnEnable, id,
-            static_cast<aidl::Effect>(effect), static_cast<aidl::EffectStrength>(strength));
-    if (!status.isOk()) {
-        ALOGE("vibratortAlwaysOnEnable command failed (%s).", status.toString8().string());
+static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong id,
+                                   jlong effect, jlong strength) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorAlwaysOnEnable failed because controller was not initialized");
+        return;
     }
+    controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
+                               static_cast<aidl::EffectStrength>(strength));
 }
 
-static void vibratorAlwaysOnDisable(JNIEnv* env, jclass, jlong id) {
-    auto status = halCall(&aidl::IVibrator::alwaysOnDisable, id);
-    if (!status.isOk()) {
-        ALOGE("vibratorAlwaysOnDisable command failed (%s).", status.toString8().string());
+static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+                                    jlong id) {
+    vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+    if (controller == nullptr) {
+        ALOGE("vibratorAlwaysOnDisable failed because controller was not initialized");
+        return;
     }
+    controller->alwaysOnDisable(static_cast<int32_t>(id));
 }
 
 static const JNINativeMethod method_table[] = {
-        {"vibratorExists", "()Z", (void*)vibratorExists},
-        {"vibratorInit", "()V", (void*)vibratorInit},
+        {"vibratorInit", "()J", (void*)vibratorInit},
+        {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
+        {"vibratorExists", "(J)Z", (void*)vibratorExists},
         {"vibratorOn", "(J)V", (void*)vibratorOn},
-        {"vibratorOff", "()V", (void*)vibratorOff},
-        {"vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
-        {"vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
+        {"vibratorOff", "(J)V", (void*)vibratorOff},
+        {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
         {"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J",
          (void*)vibratorPerformEffect},
         {"vibratorPerformComposedEffect",
          "([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
          "VibratorService$Vibration;)V",
          (void*)vibratorPerformComposedEffect},
-        {"vibratorGetSupportedEffects", "()[I", (void*)vibratorGetSupportedEffects},
-        {"vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
-        {"vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
-        {"vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
-        {"vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable},
-        {"vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable},
+        {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
+        {"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(JNIEnv *env) {
-    sMethodIdOnComplete = GetMethodIDOrDie(env,
-            FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
-            "onComplete", "()V");
-    jclass primitiveClass = FindClassOrDie(env,
-            "android/os/VibrationEffect$Composition$PrimitiveEffect");
+    sMethodIdOnComplete =
+            GetMethodIDOrDie(env,
+                             FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
+                             "onComplete", "()V");
+
+    jclass primitiveClass =
+            FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect");
     gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
     gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
     gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
-    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
-            method_table, NELEM(method_table));
+
+    return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table,
+                                    NELEM(method_table));
 }
 
-};
+}; // namespace android
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 7843663..0202c88 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -710,9 +710,8 @@
     jobject tokenObj = javaObjectForIBinder(env, token);
     jstring reasonObj = env->NewStringUTF(reason.c_str());
 
-    jlong newTimeout = env->CallLongMethod(mServiceObj,
-            gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj,
-                 reasonObj);
+    jlong newTimeout = env->CallLongMethod(mServiceObj, gServiceClassInfo.notifyANR,
+                                           inputApplicationHandleObj, tokenObj, reasonObj);
     if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
         newTimeout = 0; // abort dispatch
     } else {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7ec819f..9a2bef8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -290,6 +290,7 @@
 import com.android.server.PersistentDataBlockManagerInternal;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
@@ -775,18 +776,18 @@
         }
 
         @Override
-        public void onStartUser(int userHandle) {
-            mService.handleStartUser(userHandle);
+        public void onUserStarting(@NonNull TargetUser user) {
+            mService.handleStartUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
-            mService.handleUnlockUser(userHandle);
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            mService.handleUnlockUser(user.getUserIdentifier());
         }
 
         @Override
-        public void onStopUser(int userHandle) {
-            mService.handleStopUser(userHandle);
+        public void onUserStopping(@NonNull TargetUser user) {
+            mService.handleStopUser(user.getUserIdentifier());
         }
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ae6ccda..97ae505 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -121,9 +121,7 @@
 import com.android.server.integrity.AppIntegrityManagerService;
 import com.android.server.lights.LightsService;
 import com.android.server.location.LocationManagerService;
-import com.android.server.media.MediaResourceMonitorService;
 import com.android.server.media.MediaRouterService;
-import com.android.server.media.MediaSessionService;
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
@@ -152,6 +150,7 @@
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.power.ThermalManagerService;
+import com.android.server.profcollect.ProfcollectForwardingService;
 import com.android.server.recoverysystem.RecoverySystemService;
 import com.android.server.restrictions.RestrictionsManagerService;
 import com.android.server.role.RoleManagerService;
@@ -311,6 +310,10 @@
             "com.android.server.rollback.RollbackManagerService";
     private static final String ALARM_MANAGER_SERVICE_CLASS =
             "com.android.server.alarm.AlarmManagerService";
+    private static final String MEDIA_SESSION_SERVICE_CLASS =
+            "com.android.server.media.MediaSessionService";
+    private static final String MEDIA_RESOURCE_MONITOR_SERVICE_CLASS =
+            "com.android.server.media.MediaResourceMonitorService";
 
     private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
 
@@ -1229,6 +1232,12 @@
             mSystemServiceManager.startService(IorapForwardingService.class);
             t.traceEnd();
 
+            if (Build.IS_DEBUGGABLE) {
+                t.traceBegin("ProfcollectForwardingService");
+                mSystemServiceManager.startService(ProfcollectForwardingService.class);
+                t.traceEnd();
+            }
+
             t.traceBegin("SignedConfigService");
             SignedConfigService.registerUpdateReceiver(mSystemContext);
             t.traceEnd();
@@ -1886,7 +1895,7 @@
             t.traceEnd();
 
             t.traceBegin("StartMediaSessionService");
-            mSystemServiceManager.startService(MediaSessionService.class);
+            mSystemServiceManager.startService(MEDIA_SESSION_SERVICE_CLASS);
             t.traceEnd();
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
@@ -1910,7 +1919,7 @@
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
                 t.traceBegin("StartMediaResourceMonitor");
-                mSystemServiceManager.startService(MediaResourceMonitorService.class);
+                mSystemServiceManager.startService(MEDIA_RESOURCE_MONITOR_SERVICE_CLASS);
                 t.traceEnd();
             }
 
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 51478b3..2cfdf3f 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.midi;
 
+import android.annotation.NonNull;
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
 import android.content.Context;
@@ -47,8 +48,8 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.XmlUtils;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -75,8 +76,8 @@
         }
 
         @Override
-        public void onUnlockUser(int userHandle) {
-            if (userHandle == UserHandle.USER_SYSTEM) {
+        public void onUserUnlocking(@NonNull TargetUser user) {
+            if (user.getUserIdentifier()  == UserHandle.USER_SYSTEM) {
                 mMidiService.onUnlockUser();
             }
         }
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index d064f7e..1cdcbd8 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -72,6 +72,7 @@
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -101,13 +102,13 @@
     }
 
     @Override
-    public void onUnlockUser(int userHandle) {
-        mPrintManagerImpl.handleUserUnlocked(userHandle);
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        mPrintManagerImpl.handleUserUnlocked(user.getUserIdentifier());
     }
 
     @Override
-    public void onStopUser(int userHandle) {
-        mPrintManagerImpl.handleUserStopped(userHandle);
+    public void onUserStopping(@NonNull TargetUser user) {
+        mPrintManagerImpl.handleUserStopped(user.getUserIdentifier());
     }
 
     class PrintManagerImpl extends IPrintManager.Stub {
diff --git a/services/profcollect/Android.bp b/services/profcollect/Android.bp
new file mode 100644
index 0000000..68fba55
--- /dev/null
+++ b/services/profcollect/Android.bp
@@ -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.
+
+filegroup {
+  name: "services.profcollect-javasources",
+  srcs: ["src/**/*.java"],
+  path: "src",
+  visibility: ["//frameworks/base/services"],
+}
+
+filegroup {
+  name: "services.profcollect-sources",
+  srcs: [
+    ":services.profcollect-javasources",
+    ":profcollectd_aidl",
+  ],
+  visibility: ["//frameworks/base/services:__subpackages__"],
+}
+
+java_library_static {
+  name: "services.profcollect",
+  srcs: [":services.profcollect-sources"],
+  libs: ["services.core"],
+}
diff --git a/services/profcollect/OWNERS b/services/profcollect/OWNERS
new file mode 100644
index 0000000..b380e39
--- /dev/null
+++ b/services/profcollect/OWNERS
@@ -0,0 +1,3 @@
+srhines@google.com
+yabinc@google.com
+yikong@google.com
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
new file mode 100644
index 0000000..bc75dcd
--- /dev/null
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -0,0 +1,196 @@
+/**
+ * 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.profcollect;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import com.android.server.IoThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * System-server-local proxy into the {@code IProfcollectd} native service.
+ */
+public final class ProfcollectForwardingService extends SystemService {
+    public static final String LOG_TAG = "ProfcollectForwardingService";
+
+    private IProfCollectd mIProfcollect;
+    private ProfcollectForwardingService mSelfService;
+    private final Handler mHandler = new ProfcollectdHandler(IoThread.getHandler().getLooper());
+
+    public ProfcollectForwardingService(Context context) {
+        super(context);
+
+        if (mSelfService != null) {
+            throw new AssertionError("only one service instance allowed");
+        }
+        mSelfService = this;
+    }
+
+    @Override
+    public void onStart() {
+        Log.i(LOG_TAG, "Profcollect forwarding service start");
+        connectNativeService();
+        if (mIProfcollect == null) {
+            return;
+        }
+        if (serviceHasSupportedTraceProvider()) {
+            registerObservers();
+        }
+    }
+
+    private boolean serviceHasSupportedTraceProvider() {
+        if (mIProfcollect == null) {
+            return false;
+        }
+        try {
+            return !mIProfcollect.GetSupportedProvider().isEmpty();
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, e.getMessage());
+            return false;
+        }
+    }
+
+    private boolean tryConnectNativeService() {
+        if (connectNativeService()) {
+            return true;
+        }
+        // Cannot connect to the native service at this time, retry after a short delay.
+        mHandler.sendEmptyMessageDelayed(ProfcollectdHandler.MESSAGE_BINDER_CONNECT, 5000);
+        return false;
+    }
+
+    private boolean connectNativeService() {
+        try {
+            IProfCollectd profcollectd =
+                    IProfCollectd.Stub.asInterface(
+                            ServiceManager.getServiceOrThrow("profcollectd"));
+            profcollectd.asBinder().linkToDeath(new ProfcollectdDeathRecipient(), /*flags*/0);
+            mIProfcollect = profcollectd;
+            return true;
+        } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
+            Log.w(LOG_TAG, "Failed to connect profcollectd binder service.");
+            return false;
+        }
+    }
+
+    private class ProfcollectdHandler extends Handler {
+        public ProfcollectdHandler(Looper looper) {
+            super(looper);
+        }
+
+        public static final int MESSAGE_BINDER_CONNECT = 0;
+
+        @Override
+        public void handleMessage(android.os.Message message) {
+            switch (message.what) {
+                case MESSAGE_BINDER_CONNECT:
+                    connectNativeService();
+                    break;
+                default:
+                    throw new AssertionError("Unknown message: " + message.toString());
+            }
+        }
+    }
+
+    private class ProfcollectdDeathRecipient implements DeathRecipient {
+        @Override
+        public void binderDied() {
+            Log.w(LOG_TAG, "profcollectd has died");
+
+            mIProfcollect = null;
+            tryConnectNativeService();
+        }
+    }
+
+    // Event observers
+    private void registerObservers() {
+        registerAppLaunchObserver();
+    }
+
+    private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
+    private void registerAppLaunchObserver() {
+        ActivityTaskManagerInternal atmInternal =
+                LocalServices.getService(ActivityTaskManagerInternal.class);
+        ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+                atmInternal.getLaunchObserverRegistry();
+        launchObserverRegistry.registerLaunchObserver(mAppLaunchObserver);
+    }
+
+    private void traceOnAppStart(String packageName) {
+        if (mIProfcollect == null) {
+            return;
+        }
+
+        // Sample for a fraction of app launches.
+        int traceFrequency = SystemProperties.getInt("profcollectd.applaunch_trace_freq", 2);
+        int randomNum = ThreadLocalRandom.current().nextInt(100);
+        if (randomNum < traceFrequency) {
+            try {
+                Log.i(LOG_TAG, "Tracing on app launch event: " + packageName);
+                mIProfcollect.TraceOnce("applaunch");
+            } catch (RemoteException e) {
+                Log.e(LOG_TAG, e.getMessage());
+            }
+        }
+    }
+
+    private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
+        @Override
+        public void onIntentStarted(Intent intent, long timestampNanos) {
+            traceOnAppStart(intent.getPackage());
+        }
+
+        @Override
+        public void onIntentFailed() {
+            // Ignored
+        }
+
+        @Override
+        public void onActivityLaunched(byte[] activity, int temperature) {
+            // Ignored
+        }
+
+        @Override
+        public void onActivityLaunchCancelled(byte[] abortingActivity) {
+            // Ignored
+        }
+
+        @Override
+        public void onActivityLaunchFinished(byte[] finalActivity, long timestampNanos) {
+            // Ignored
+        }
+
+        @Override
+        public void onReportFullyDrawn(byte[] activity, long timestampNanos) {
+            // Ignored
+        }
+    }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index 4a73efe..cd9b6ac 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -38,7 +38,6 @@
 
 import android.annotation.UserIdInt;
 import android.app.Application;
-import android.app.backup.BackupManager;
 import android.app.backup.BackupManager.OperationType;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IBackupObserver;
@@ -46,6 +45,7 @@
 import android.app.backup.ISelectBackupTransportCallback;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.UserInfo;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -54,6 +54,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseArray;
 
+import com.android.server.SystemService.TargetUser;
 import com.android.server.backup.testing.TransportData;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowBinder;
@@ -1601,7 +1602,7 @@
         BackupManagerService.Lifecycle lifecycle =
                 new BackupManagerService.Lifecycle(mContext, backupManagerService);
 
-        lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
+        lifecycle.onUserUnlocking(new TargetUser(new UserInfo(UserHandle.USER_SYSTEM, null, 0)));
 
         verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
     }
@@ -1613,7 +1614,7 @@
         BackupManagerService.Lifecycle lifecycle =
                 new BackupManagerService.Lifecycle(mContext, backupManagerService);
 
-        lifecycle.onStopUser(UserHandle.USER_SYSTEM);
+        lifecycle.onUserStopping(new TargetUser(new UserInfo(UserHandle.USER_SYSTEM, null, 0)));
 
         verify(backupManagerService).onStopUser(UserHandle.USER_SYSTEM);
     }
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 44eb828..a398961 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -17,6 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.mockingservicestests">
 
+    <uses-sdk android:targetSdkVersion="30" />
+
     <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
     <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index 8ccaedd..2f5e883 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -247,7 +247,7 @@
                 .thenAnswer(inv -> getPowerSaveState());
         when(mMockAppOpsManager.getPackagesForOps(
                 any(int[].class)
-                )).thenAnswer(mGetPackagesForOps);
+        )).thenAnswer(mGetPackagesForOps);
 
         mMockContentResolver = new MockContentResolver();
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
@@ -447,7 +447,7 @@
         areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
 
-        // Clear the app ops and update the whitelist.
+        // Clear the app ops and update the exemption list.
         setAppOps(UID_1, PACKAGE_1, false);
         setAppOps(UID_10_2, PACKAGE_2, false);
 
@@ -462,7 +462,8 @@
         areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1}, new int[] {}, new int[] {UID_2});
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_1}, new int[] {},
+                new int[] {UID_2});
 
         areRestricted(instance, UID_1, PACKAGE_1, NONE);
         areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
@@ -487,24 +488,25 @@
         areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
 
-        assertTrue(instance.isUidPowerSaveWhitelisted(UID_1));
-        assertTrue(instance.isUidPowerSaveWhitelisted(UID_10_1));
-        assertFalse(instance.isUidPowerSaveWhitelisted(UID_2));
-        assertFalse(instance.isUidPowerSaveWhitelisted(UID_10_2));
+        assertTrue(instance.isUidPowerSaveExempt(UID_1));
+        assertTrue(instance.isUidPowerSaveExempt(UID_10_1));
+        assertFalse(instance.isUidPowerSaveExempt(UID_2));
+        assertFalse(instance.isUidPowerSaveExempt(UID_10_2));
 
-        assertFalse(instance.isUidTempPowerSaveWhitelisted(UID_1));
-        assertFalse(instance.isUidTempPowerSaveWhitelisted(UID_10_1));
-        assertTrue(instance.isUidTempPowerSaveWhitelisted(UID_2));
-        assertTrue(instance.isUidTempPowerSaveWhitelisted(UID_10_2));
+        assertFalse(instance.isUidTempPowerSaveExempt(UID_1));
+        assertFalse(instance.isUidTempPowerSaveExempt(UID_10_1));
+        assertTrue(instance.isUidTempPowerSaveExempt(UID_2));
+        assertTrue(instance.isUidTempPowerSaveExempt(UID_10_2));
     }
 
     @Test
-    public void testPowerSaveUserWhitelist() throws Exception {
+    public void testPowerSaveUserExemptionList() throws Exception {
         final AppStateTrackerTestable instance = newInstance();
-        instance.setPowerSaveWhitelistAppIds(new int[] {}, new int[] {UID_1, UID_2}, new int[] {});
-        assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_1));
-        assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_2));
-        assertFalse(instance.isUidPowerSaveUserWhitelisted(UID_3));
+        instance.setPowerSaveExemptionListAppIds(new int[] {}, new int[] {UID_1, UID_2},
+                new int[] {});
+        assertTrue(instance.isUidPowerSaveUserExempt(UID_1));
+        assertTrue(instance.isUidPowerSaveUserExempt(UID_2));
+        assertFalse(instance.isUidPowerSaveUserExempt(UID_3));
     }
 
     @Test
@@ -909,9 +911,10 @@
         reset(l);
 
         // -------------------------------------------------------------------------
-        // Tests with system/user/temp whitelist.
+        // Tests with system/user/temp exemption list.
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_1, UID_2}, new int[] {},
+                new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -923,7 +926,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -935,8 +938,8 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        // Update temp whitelist.
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+        // Update temp exemption list.
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
                 new int[] {UID_1, UID_3});
 
         waitUntilMainHandlerDrain();
@@ -949,7 +952,8 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
+                new int[] {UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -975,10 +979,11 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_1, UID_2}, new int[] {},
+                new int[] {});
 
         waitUntilMainHandlerDrain();
-        // Called once for updating all whitelist and once for updating temp whitelist
+        // Called once for updating all exemption list and once for updating temp exemption list
         verify(l, times(2)).updateAllJobs();
         verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
         verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -988,7 +993,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -1000,8 +1005,8 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        // Update temp whitelist.
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+        // Update temp exemption list.
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
                 new int[] {UID_1, UID_3});
 
         waitUntilMainHandlerDrain();
@@ -1014,7 +1019,8 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
+        instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
+                new int[] {UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -1254,7 +1260,7 @@
                 .mapToInt(Integer::intValue).toArray();
     }
 
-    static boolean isAnyAppIdUnwhitelistedSlow(int[] prevArray, int[] newArray) {
+    static boolean isAnyAppIdUnexemptSlow(int[] prevArray, int[] newArray) {
         Arrays.sort(newArray); // Just in case...
         for (int p : prevArray) {
             if (Arrays.binarySearch(newArray, p) < 0) {
@@ -1264,31 +1270,31 @@
         return false;
     }
 
-    private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) {
+    private void checkAnyAppIdUnexempt(int[] prevArray, int[] newArray, boolean expected) {
         assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
-                expected, AppStateTrackerImpl.isAnyAppIdUnwhitelisted(prevArray, newArray));
+                expected, AppStateTrackerImpl.isAnyAppIdUnexempt(prevArray, newArray));
 
-        // Also test isAnyAppIdUnwhitelistedSlow.
+        // Also test isAnyAppIdUnexempt.
         assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
-                expected, isAnyAppIdUnwhitelistedSlow(prevArray, newArray));
+                expected, isAnyAppIdUnexemptSlow(prevArray, newArray));
     }
 
     @Test
-    public void isAnyAppIdUnwhitelisted() {
-        checkAnyAppIdUnwhitelisted(array(), array(), false);
+    public void isAnyAppIdUnexempt() {
+        checkAnyAppIdUnexempt(array(), array(), false);
 
-        checkAnyAppIdUnwhitelisted(array(1), array(), true);
-        checkAnyAppIdUnwhitelisted(array(1), array(1), false);
-        checkAnyAppIdUnwhitelisted(array(1), array(0, 1), false);
-        checkAnyAppIdUnwhitelisted(array(1), array(0, 1, 2), false);
-        checkAnyAppIdUnwhitelisted(array(1), array(0, 1, 2), false);
+        checkAnyAppIdUnexempt(array(1), array(), true);
+        checkAnyAppIdUnexempt(array(1), array(1), false);
+        checkAnyAppIdUnexempt(array(1), array(0, 1), false);
+        checkAnyAppIdUnexempt(array(1), array(0, 1, 2), false);
+        checkAnyAppIdUnexempt(array(1), array(0, 1, 2), false);
 
-        checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(), true);
-        checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(1, 2), true);
-        checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(1, 2, 10), false);
-        checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(2, 10), true);
-        checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(0, 1, 2, 4, 3, 10), false);
-        checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(0, 0, 1, 2, 10), false);
+        checkAnyAppIdUnexempt(array(1, 2, 10), array(), true);
+        checkAnyAppIdUnexempt(array(1, 2, 10), array(1, 2), true);
+        checkAnyAppIdUnexempt(array(1, 2, 10), array(1, 2, 10), false);
+        checkAnyAppIdUnexempt(array(1, 2, 10), array(2, 10), true);
+        checkAnyAppIdUnexempt(array(1, 2, 10), array(0, 1, 2, 4, 3, 10), false);
+        checkAnyAppIdUnexempt(array(1, 2, 10), array(0, 0, 1, 2, 10), false);
 
         // Random test
         int trueCount = 0;
@@ -1297,8 +1303,8 @@
             final int[] array1 = makeRandomArray();
             final int[] array2 = makeRandomArray();
 
-            final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2);
-            final boolean actual = AppStateTrackerImpl.isAnyAppIdUnwhitelisted(array1, array2);
+            final boolean expected = isAnyAppIdUnexemptSlow(array1, array2);
+            final boolean actual = AppStateTrackerImpl.isAnyAppIdUnexempt(array1, array2);
 
             assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2),
                     expected, actual);
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 0a61c44..7a3a950 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -130,7 +130,9 @@
     }
 
     @After
-    public void resetStaticMocks() {
+    public void tearDown() {
+        mAppOpsService.shutdown();
+
         mMockingSession.finishMocking();
     }
 
@@ -216,9 +218,8 @@
                 false);
         mAppOpsService.writeState();
 
-        // Create a new app ops service, and initialize its state from XML.
+        // Create a new app ops service which will initialize its state from XML.
         setupAppOpsService();
-        mAppOpsService.readState();
 
         // Query the state of the 2nd service.
         List<PackageOps> loggedOps = getLoggedOps();
@@ -233,9 +234,8 @@
         mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
         mAppOpsService.shutdown();
 
-        // Create a new app ops service, and initialize its state from XML.
+        // Create a new app ops service which will initialize its state from XML.
         setupAppOpsService();
-        mAppOpsService.readState();
 
         // Query the state of the 2nd service.
         List<PackageOps> loggedOps = getLoggedOps();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
new file mode 100644
index 0000000..1cb004a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -0,0 +1,971 @@
+/*
+ * 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.location;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.WINDOW_EXACT;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
+import static android.location.Criteria.ACCURACY_COARSE;
+import static android.location.Criteria.ACCURACY_FINE;
+import static android.location.Criteria.POWER_HIGH;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
+
+import static androidx.test.ext.truth.location.LocationSubject.assertThat;
+
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
+import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationUtils.createLocation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
+import android.content.Context;
+import android.location.ILocationCallback;
+import android.location.ILocationListener;
+import android.location.Location;
+import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
+import android.location.LocationRequest;
+import android.location.util.identity.CallerIdentity;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.ICancellationSignal;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.WorkSource;
+import android.platform.test.annotations.Presubmit;
+import android.util.Log;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.location.listeners.ListenerRegistration;
+import com.android.server.location.util.FakeUserInfoHelper;
+import com.android.server.location.util.TestInjector;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocationProviderManagerTest {
+
+    private static final String TAG = "LocationProviderManagerTest";
+
+    private static final long TIMEOUT_MS = 1000;
+
+    private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+    private static final int OTHER_USER = CURRENT_USER + 10;
+
+    private static final String NAME = "test";
+    private static final ProviderProperties PROPERTIES = new ProviderProperties(false, false, false,
+            false, true, true, true, POWER_HIGH, ACCURACY_FINE);
+    private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
+            "mypackage",
+            "attribution");
+
+    private Random mRandom;
+
+    @Mock
+    private LocationManagerInternal mInternal;
+    @Mock
+    private Context mContext;
+    @Mock
+    private AlarmManager mAlarmManager;
+    @Mock
+    private PowerManager mPowerManager;
+    @Mock
+    private PowerManager.WakeLock mWakeLock;
+
+    private TestInjector mInjector;
+    private PassiveLocationProviderManager mPassive;
+    private TestProvider mProvider;
+
+    private LocationProviderManager mManager;
+
+    @Before
+    public void setUp() {
+        initMocks(this);
+
+        long seed = System.currentTimeMillis();
+        Log.i(TAG, "location random seed: " + seed);
+
+        mRandom = new Random(seed);
+
+        LocalServices.addService(LocationManagerInternal.class, mInternal);
+
+        doReturn("android").when(mContext).getPackageName();
+        doReturn(mAlarmManager).when(mContext).getSystemService(AlarmManager.class);
+        doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+        doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+
+        mInjector = new TestInjector();
+        mInjector.getUserInfoHelper().startUser(OTHER_USER);
+
+        mPassive = new PassiveLocationProviderManager(mContext, mInjector);
+        mPassive.startManager();
+        mPassive.setRealProvider(new PassiveProvider(mContext));
+
+        mProvider = new TestProvider(PROPERTIES, IDENTITY);
+        mProvider.setProviderAllowed(true);
+
+        mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive);
+        mManager.startManager();
+        mManager.setRealProvider(mProvider);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(LocationManagerInternal.class);
+
+        // some test failures may leave the fg thread stuck, interrupt until we get out of it
+        CountDownLatch latch = new CountDownLatch(1);
+        FgThread.getExecutor().execute(latch::countDown);
+        int count = 0;
+        while (++count < 10 && !latch.await(10, TimeUnit.MILLISECONDS)) {
+            FgThread.get().getLooper().getThread().interrupt();
+        }
+    }
+
+    @Test
+    public void testProperties() {
+        assertThat(mManager.getName()).isEqualTo(NAME);
+        assertThat(mManager.getProperties()).isEqualTo(PROPERTIES);
+        assertThat(mManager.getIdentity()).isEqualTo(IDENTITY);
+        assertThat(mManager.hasProvider()).isTrue();
+
+        ProviderProperties newProperties = new ProviderProperties(true, true, true,
+                true, false, false, false, POWER_HIGH, ACCURACY_COARSE);
+        mProvider.setProperties(newProperties);
+        assertThat(mManager.getProperties()).isEqualTo(newProperties);
+
+        CallerIdentity newIdentity = CallerIdentity.forTest(OTHER_USER, 1, "otherpackage",
+                "otherattribution");
+        mProvider.setIdentity(newIdentity);
+        assertThat(mManager.getIdentity()).isEqualTo(newIdentity);
+
+        mManager.setRealProvider(null);
+        assertThat(mManager.hasProvider()).isFalse();
+    }
+
+    @Test
+    public void testRemoveProvider() {
+        mManager.setRealProvider(null);
+        assertThat(mManager.hasProvider()).isFalse();
+    }
+
+    @Test
+    public void testIsEnabled() {
+        assertThat(mManager.isEnabled(CURRENT_USER)).isTrue();
+
+        mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+        assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+
+        mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+        mProvider.setAllowed(false);
+        assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+
+        mProvider.setAllowed(true);
+        mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+        assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+        assertThat(mManager.isEnabled(OTHER_USER)).isTrue();
+
+        mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+        assertThat(mManager.isEnabled(CURRENT_USER)).isTrue();
+        assertThat(mManager.isEnabled(OTHER_USER)).isFalse();
+    }
+
+    @Test
+    public void testIsEnabledListener() {
+        ProviderEnabledListener listener = mock(ProviderEnabledListener.class);
+        mManager.addEnabledListener(listener);
+        verify(listener, never()).onProviderEnabledChanged(anyString(), anyInt(), anyBoolean());
+
+        mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, CURRENT_USER,
+                false);
+
+        mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, CURRENT_USER,
+                true);
+
+        mProvider.setAllowed(false);
+        verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, CURRENT_USER,
+                false);
+
+        mProvider.setAllowed(true);
+        verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, CURRENT_USER,
+                true);
+
+        mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, CURRENT_USER,
+                false);
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, OTHER_USER,
+                true);
+
+        mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, CURRENT_USER,
+                true);
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, OTHER_USER,
+                false);
+
+        mManager.removeEnabledListener(listener);
+        mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+        verifyNoMoreInteractions(listener);
+    }
+
+    @Test
+    public void testGetLastLocation_Fine() {
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+    }
+
+    @Test
+    public void testGetLastLocation_Coarse() {
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        Location coarse = mManager.getLastLocation(request, IDENTITY, PERMISSION_COARSE);
+        assertThat(coarse).isNotEqualTo(loc);
+        assertThat(coarse).isNearby(loc, 5000);
+    }
+
+    @Test
+    public void testGetLastLocation_Bypass() {
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+        LocationRequest bypassRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false).setLocationSettingsIgnored(true);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isNull();
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+        assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+                loc);
+
+        mProvider.setProviderAllowed(false);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+                loc);
+
+        loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+                loc);
+
+        mProvider.setProviderAllowed(true);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+                loc);
+
+        loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+        assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+                loc);
+    }
+
+    @Test
+    public void testGetLastLocation_ClearOnMockRemoval() {
+        MockProvider mockProvider = new MockProvider(PROPERTIES, IDENTITY);
+        mockProvider.setAllowed(true);
+        mManager.setMockProvider(mockProvider);
+
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+        Location loc = createLocation(NAME, mRandom);
+        mockProvider.setProviderLocation(loc);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+
+        mManager.setMockProvider(null);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+    }
+
+    @Test
+    public void testInjectLastLocation() {
+        Location loc1 = createLocation(NAME, mRandom);
+        mManager.injectLastLocation(loc1, CURRENT_USER);
+
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+
+        Location loc2 = createLocation(NAME, mRandom);
+        mManager.injectLastLocation(loc2, CURRENT_USER);
+
+        assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+    }
+
+    @Test
+    public void testPassive_Listener() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
+                0, false);
+        mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+
+        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+        verify(listener).onLocationChanged(locationCaptor.capture(),
+                nullable(IRemoteCallback.class));
+        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+    }
+
+    @Test
+    public void testPassive_LastLocation() {
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
+                0, false);
+        assertThat(mPassive.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+    }
+
+    @Test
+    public void testRegisterListener() throws Exception {
+        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+        ILocationListener listener = createMockLocationListener();
+        mManager.registerLocationRequest(
+                LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+                PERMISSION_FINE, listener);
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        verify(listener, times(1)).onLocationChanged(locationCaptor.capture(),
+                nullable(IRemoteCallback.class));
+        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+
+        mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, false);
+        loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        verify(listener, times(1)).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+
+        mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, true);
+
+        mProvider.setAllowed(false);
+        verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, false);
+        loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        verify(listener, times(1)).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+
+        mProvider.setAllowed(true);
+        verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, true);
+
+        mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, false);
+        loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        verify(listener, times(1)).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+
+        mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+        verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, true);
+
+        loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        verify(listener, times(2)).onLocationChanged(locationCaptor.capture(),
+                nullable(IRemoteCallback.class));
+        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+    }
+
+    @Test
+    public void testRegisterListener_SameProcess() throws Exception {
+        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+        CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+                "attribution");
+
+        ILocationListener listener = createMockLocationListener();
+        mManager.registerLocationRequest(
+                LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+                PERMISSION_FINE, listener);
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(locationCaptor.capture(),
+                nullable(IRemoteCallback.class));
+        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+    }
+
+    @Test
+    public void testRegisterListener_Unregister() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        mManager.registerLocationRequest(
+                LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+                PERMISSION_FINE, listener);
+        mManager.unregisterLocationRequest(listener);
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        verify(listener, never()).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+
+        mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+        verify(listener, after(TIMEOUT_MS).never()).onProviderEnabledChanged(NAME, false);
+    }
+
+    @Test
+    public void testRegisterListener_Unregister_SameProcess() throws Exception {
+        CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+                "attribution");
+
+        ILocationListener listener = createMockLocationListener();
+        mManager.registerLocationRequest(
+                LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+                PERMISSION_FINE, listener);
+
+        CountDownLatch blocker = new CountDownLatch(1);
+        ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+            try {
+                blocker.await();
+            } catch (InterruptedException e) {
+                // do nothing
+            }
+        });
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        mManager.unregisterLocationRequest(listener);
+        blocker.countDown();
+        verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_NumUpdates() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false).setNumUpdates(5);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+        verify(listener, times(5)).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_ExpiringAlarm() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false).setExpireIn(5000);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+        long baseTimeMs = SystemClock.elapsedRealtime();
+
+        ArgumentCaptor<Long> timeoutCapture = ArgumentCaptor.forClass(Long.class);
+        ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
+                OnAlarmListener.class);
+        verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), timeoutCapture.capture(),
+                eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
+                any(WorkSource.class));
+
+        assertThat(timeoutCapture.getValue()).isAtLeast(baseTimeMs + 4000);
+        assertThat(timeoutCapture.getValue()).isAtMost(baseTimeMs + 5000);
+        listenerCapture.getValue().onAlarm();
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        verify(listener, never()).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_ExpiringNoAlarm() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false).setExpireIn(25);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        Thread.sleep(25);
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        verify(listener, never()).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_AlreadyExpired() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false).setExpireIn(-1);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        verify(listener, never()).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_FastestInterval() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
+                false).setFastestInterval(5000);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+        verify(listener, times(1)).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_SmallestDisplacement() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
+                false).setSmallestDisplacement(1f);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        mProvider.setProviderLocation(loc);
+
+        verify(listener, times(1)).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_NoteOpFailure() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, IDENTITY.getPackageName(),
+                false);
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+        verify(listener, never()).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+    }
+
+    @Test
+    public void testRegisterListener_Wakelock() throws Exception {
+        CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+                "attribution");
+
+        ILocationListener listener = createMockLocationListener();
+        mManager.registerLocationRequest(
+                LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+                PERMISSION_FINE, listener);
+
+        CountDownLatch blocker = new CountDownLatch(1);
+        ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+            try {
+                blocker.await();
+            } catch (InterruptedException e) {
+                // do nothing
+            }
+        });
+
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        verify(mWakeLock).acquire(anyLong());
+        verify(mWakeLock, never()).release();
+
+        blocker.countDown();
+        verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(Location.class),
+                nullable(IRemoteCallback.class));
+        verify(mWakeLock).acquire(anyLong());
+        verify(mWakeLock, timeout(TIMEOUT_MS)).release();
+    }
+
+    @Test
+    public void testGetCurrentLocation() throws Exception {
+        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+        ILocationCallback listener = createMockGetCurrentLocationListener();
+        LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false);
+        ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+        mManager.getCurrentLocation(locationRequest, IDENTITY,
+                PERMISSION_FINE, cancellationSignal, listener);
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+        verify(listener, times(1)).onLocation(locationCaptor.capture());
+        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+    }
+
+    @Test
+    public void testGetCurrentLocation_Cancel() throws Exception {
+        ILocationCallback listener = createMockGetCurrentLocationListener();
+        LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false);
+        ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+        mManager.getCurrentLocation(locationRequest, IDENTITY,
+                PERMISSION_FINE, cancellationSignal, listener);
+
+        cancellationSignal.cancel();
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+        verify(listener, never()).onLocation(nullable(Location.class));
+    }
+
+    @Test
+    public void testGetCurrentLocation_ProviderDisabled() throws Exception {
+        ILocationCallback listener = createMockGetCurrentLocationListener();
+        LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false);
+        ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+        mManager.getCurrentLocation(locationRequest, IDENTITY,
+                PERMISSION_FINE, cancellationSignal, listener);
+
+        mProvider.setProviderAllowed(false);
+        mProvider.setProviderAllowed(true);
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        verify(listener, times(1)).onLocation(isNull());
+    }
+
+    @Test
+    public void testGetCurrentLocation_ProviderAlreadyDisabled() throws Exception {
+        mProvider.setProviderAllowed(false);
+
+        ILocationCallback listener = createMockGetCurrentLocationListener();
+        LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false);
+        ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+        mManager.getCurrentLocation(locationRequest, IDENTITY,
+                PERMISSION_FINE, cancellationSignal, listener);
+
+        mProvider.setProviderAllowed(true);
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+        verify(listener, times(1)).onLocation(isNull());
+    }
+
+    @Test
+    public void testGetCurrentLocation_LastLocation() throws Exception {
+        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+
+        ILocationCallback listener = createMockGetCurrentLocationListener();
+        LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false);
+        ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+        mManager.getCurrentLocation(locationRequest, IDENTITY,
+                PERMISSION_FINE, cancellationSignal, listener);
+
+        verify(listener, times(1)).onLocation(locationCaptor.capture());
+        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+    }
+
+    @Test
+    public void testGetCurrentLocation_Timeout() throws Exception {
+        ILocationCallback listener = createMockGetCurrentLocationListener();
+        LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+                false);
+        ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+        mManager.getCurrentLocation(locationRequest, IDENTITY,
+                PERMISSION_FINE, cancellationSignal, listener);
+
+        ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
+                OnAlarmListener.class);
+        verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), anyLong(),
+                eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
+                any(WorkSource.class));
+        listenerCapture.getValue().onAlarm();
+
+        verify(listener, times(1)).onLocation(isNull());
+    }
+
+    @Test
+    public void testLocationMonitoring() {
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                IDENTITY.getPackageName())).isFalse();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                IDENTITY.getPackageName())).isFalse();
+
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                IDENTITY.getPackageName())).isTrue();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                IDENTITY.getPackageName())).isTrue();
+
+        mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                IDENTITY.getPackageName())).isTrue();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                IDENTITY.getPackageName())).isFalse();
+
+        mManager.unregisterLocationRequest(listener);
+
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+                IDENTITY.getPackageName())).isFalse();
+        assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+                IDENTITY.getPackageName())).isFalse();
+    }
+
+    @Test
+    public void testProviderRequest() {
+        assertThat(mProvider.getRequest().reportLocation).isFalse();
+        assertThat(mProvider.getRequest().locationRequests).isEmpty();
+
+        ILocationListener listener1 = createMockLocationListener();
+        LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+        mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+        assertThat(mProvider.getRequest().reportLocation).isTrue();
+        assertThat(mProvider.getRequest().locationRequests).containsExactly(request1);
+        assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+        assertThat(mProvider.getRequest().interval).isEqualTo(5);
+        assertThat(mProvider.getRequest().lowPowerMode).isFalse();
+        assertThat(mProvider.getRequest().workSource).isNotNull();
+
+        ILocationListener listener2 = createMockLocationListener();
+        LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+                false).setLowPowerMode(true);
+        mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+        assertThat(mProvider.getRequest().reportLocation).isTrue();
+        assertThat(mProvider.getRequest().locationRequests).containsExactly(request1, request2);
+        assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+        assertThat(mProvider.getRequest().interval).isEqualTo(1);
+        assertThat(mProvider.getRequest().lowPowerMode).isFalse();
+        assertThat(mProvider.getRequest().workSource).isNotNull();
+
+        mManager.unregisterLocationRequest(listener1);
+
+        assertThat(mProvider.getRequest().reportLocation).isTrue();
+        assertThat(mProvider.getRequest().locationRequests).containsExactly(request2);
+        assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+        assertThat(mProvider.getRequest().interval).isEqualTo(1);
+        assertThat(mProvider.getRequest().lowPowerMode).isTrue();
+        assertThat(mProvider.getRequest().workSource).isNotNull();
+
+        mManager.unregisterLocationRequest(listener2);
+
+        assertThat(mProvider.getRequest().reportLocation).isFalse();
+        assertThat(mProvider.getRequest().locationRequests).isEmpty();
+    }
+
+    @Test
+    public void testProviderRequest_BackgroundThrottle() {
+        ILocationListener listener1 = createMockLocationListener();
+        LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+        mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+        assertThat(mProvider.getRequest().interval).isEqualTo(5);
+
+        mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+        assertThat(mProvider.getRequest().interval).isEqualTo(
+                mInjector.getSettingsHelper().getBackgroundThrottleIntervalMs());
+    }
+
+    @Test
+    public void testProviderRequest_IgnoreLocationSettings() {
+        mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+                Collections.singleton(IDENTITY.getPackageName()));
+
+        ILocationListener listener1 = createMockLocationListener();
+        LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+        mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+        assertThat(mProvider.getRequest().reportLocation).isTrue();
+        assertThat(mProvider.getRequest().interval).isEqualTo(5);
+        assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+
+        ILocationListener listener2 = createMockLocationListener();
+        LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+                false).setLocationSettingsIgnored(true);
+        mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+        assertThat(mProvider.getRequest().reportLocation).isTrue();
+        assertThat(mProvider.getRequest().interval).isEqualTo(1);
+        assertThat(mProvider.getRequest().locationSettingsIgnored).isTrue();
+    }
+
+    @Test
+    public void testProviderRequest_IgnoreLocationSettings_ProviderDisabled() {
+        mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+                Collections.singleton(IDENTITY.getPackageName()));
+
+        ILocationListener listener1 = createMockLocationListener();
+        LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0, false);
+        mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+        ILocationListener listener2 = createMockLocationListener();
+        LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
+                false).setLocationSettingsIgnored(true);
+        mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+        mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
+
+        assertThat(mProvider.getRequest().reportLocation).isTrue();
+        assertThat(mProvider.getRequest().locationRequests).containsExactly(request2);
+        assertThat(mProvider.getRequest().interval).isEqualTo(5);
+        assertThat(mProvider.getRequest().locationSettingsIgnored).isTrue();
+    }
+
+    @Test
+    public void testProviderRequest_IgnoreLocationSettings_NoAllowlist() {
+        mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+                Collections.singleton(IDENTITY.getPackageName()));
+
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+                false).setLocationSettingsIgnored(true);
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(Collections.emptySet());
+
+        assertThat(mProvider.getRequest().reportLocation).isTrue();
+        assertThat(mProvider.getRequest().interval).isEqualTo(1);
+        assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+    }
+
+    @Test
+    public void testProviderRequest_BackgroundThrottle_IgnoreLocationSettings() {
+        mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+                Collections.singleton(IDENTITY.getPackageName()));
+
+        ILocationListener listener1 = createMockLocationListener();
+        LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
+                false).setLocationSettingsIgnored(true);
+        mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+        assertThat(mProvider.getRequest().interval).isEqualTo(5);
+
+        mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+        assertThat(mProvider.getRequest().interval).isEqualTo(5);
+    }
+
+    private ILocationListener createMockLocationListener() {
+        return spy(new ILocationListener.Stub() {
+            @Override
+            public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
+                if (onCompleteCallback != null) {
+                    try {
+                        onCompleteCallback.sendResult(null);
+                    } catch (RemoteException e) {
+                        e.rethrowFromSystemServer();
+                    }
+                }
+            }
+
+            @Override
+            public void onProviderEnabledChanged(String provider, boolean enabled) {
+            }
+        });
+    }
+
+    private ILocationCallback createMockGetCurrentLocationListener() {
+        return spy(new ILocationCallback.Stub() {
+            @Override
+            public void onLocation(Location location) {
+            }
+        });
+    }
+
+    private static class TestProvider extends AbstractLocationProvider {
+
+        private ProviderRequest mProviderRequest = ProviderRequest.EMPTY_REQUEST;
+
+        TestProvider(ProviderProperties properties, CallerIdentity identity) {
+            super(DIRECT_EXECUTOR, identity);
+            setProperties(properties);
+        }
+
+        public void setProviderAllowed(boolean allowed) {
+            setAllowed(allowed);
+        }
+
+        public void setProviderLocation(Location l) {
+            reportLocation(new Location(l));
+        }
+
+        public ProviderRequest getRequest() {
+            return mProviderRequest;
+        }
+
+        @Override
+        public void onSetRequest(ProviderRequest request) {
+            mProviderRequest = request;
+        }
+
+        @Override
+        protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index c692253..1b6ac3c 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -183,13 +183,12 @@
 
     @Test
     public void hasAmplitudeControl_withAmplitudeControlSupport_returnsTrue() {
-        when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         assertTrue(createService().hasAmplitudeControl());
     }
 
     @Test
     public void hasAmplitudeControl_withNoAmplitudeControlSupport_returnsFalse() {
-        when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(false);
         assertFalse(createService().hasAmplitudeControl());
     }
 
@@ -270,7 +269,7 @@
 
     @Test
     public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
-        when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
         Mockito.clearInvocations(mNativeWrapperMock);
 
@@ -340,7 +339,7 @@
     @Test
     public void vibrate_withWaveform_controlsVibratorAmplitudeDuringTotalVibrationTime()
             throws Exception {
-        when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
         Mockito.clearInvocations(mNativeWrapperMock);
 
@@ -511,7 +510,7 @@
         setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
 
-        when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
         service.systemReady();
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index a9f2e4a..57bfbf3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -95,12 +96,15 @@
 
     ValueAnimator mMockValueAnimator;
     ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
+    ValueAnimator.AnimatorListener mStateListener;
 
     FullScreenMagnificationController mFullScreenMagnificationController;
+    Runnable mEndCallback;
 
     @Before
     public void setUp() {
         Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+        mEndCallback = Mockito.mock(Runnable.class);
         // Pretending ID of the Thread associated with looper as main thread ID in controller
         when(mMockContext.getMainLooper()).thenReturn(looper);
         when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
@@ -319,6 +323,7 @@
         for (int i = 0; i < DISPLAY_COUNT; i++) {
             setScaleAndCenter_animated_stateChangesAndAnimationHappens(i);
             resetMockWindowManager();
+            Mockito.reset(mEndCallback);
         }
     }
 
@@ -331,7 +336,7 @@
         MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
 
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId, scale,
-                newCenter.x, newCenter.y, true, SERVICE_ID_1));
+                newCenter.x, newCenter.y, mEndCallback, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(newCenter.x, mFullScreenMagnificationController.getCenterX(displayId), 0.5);
@@ -358,7 +363,33 @@
         Mockito.reset(mMockWindowManager);
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        mStateListener.onAnimationEnd(mMockValueAnimator);
         verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
+        verify(mEndCallback).run();
+    }
+
+    @Test
+    public void testSetScaleAndCenterWithAnimation_sameSpec_noAnimationButInvokeEndCallback() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setScaleAndCenter_sameSpec_noAnimationButInvokeEndCallback(i);
+            Mockito.reset(mEndCallback);
+        }
+    }
+
+    private void setScaleAndCenter_sameSpec_noAnimationButInvokeEndCallback(int displayId) {
+        register(displayId);
+        final PointF center = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        final float targetScale = 2.0f;
+        assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
+                targetScale, center.x, center.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
+
+        assertFalse(mFullScreenMagnificationController.setScaleAndCenter(displayId,
+                targetScale, center.x, center.y, mEndCallback, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
+
+        verify(mMockValueAnimator, never()).start();
+        verify(mEndCallback).run();
     }
 
     @Test
@@ -639,6 +670,69 @@
     }
 
     @Test
+    public void testReset_notMagnifying_noStateChangeButInvokeCallback() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            reset_notMagnifying_noStateChangeButInvokeCallback(i);
+            Mockito.reset(mEndCallback);
+        }
+    }
+
+    private void reset_notMagnifying_noStateChangeButInvokeCallback(int displayId) {
+        register(displayId);
+
+        assertFalse(mFullScreenMagnificationController.reset(displayId, mEndCallback));
+        mMessageCapturingHandler.sendAllMessages();
+
+        verify(mMockAms, never()).notifyMagnificationChanged(eq(displayId),
+                any(Region.class), anyFloat(), anyFloat(), anyFloat());
+        verify(mEndCallback).run();
+    }
+
+    @Test
+    public void testReset_Magnifying_resetsMagnificationAndInvokeLastEndCallback() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            reset_Magnifying_resetsMagnificationAndInvokeLastEndCallback(i);
+        }
+    }
+
+    private void reset_Magnifying_resetsMagnificationAndInvokeLastEndCallback(int displayId) {
+        register(displayId);
+        float scale = 2.5f;
+        PointF firstCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
+                scale, firstCenter.x, firstCenter.y, mEndCallback, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
+        Mockito.reset(mMockValueAnimator);
+        // Stubs the logic after the animation is started.
+        doAnswer(invocation -> {
+            mStateListener.onAnimationEnd(mMockValueAnimator);
+            return null;
+        }).when(mMockValueAnimator).cancel();
+        when(mMockValueAnimator.isRunning()).thenReturn(true);
+        // Intermediate point
+        float fraction = 0.33f;
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        Runnable lastEndCallback = Mockito.mock(Runnable.class);
+
+        assertTrue(mFullScreenMagnificationController.reset(displayId, lastEndCallback));
+        mMessageCapturingHandler.sendAllMessages();
+
+        // Verify expected actions.
+        verify(mEndCallback, never()).run();
+        verify(mMockValueAnimator).start();
+        verify(mMockValueAnimator).cancel();
+
+        // Fast-forward the animation to the end.
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        mStateListener.onAnimationEnd(mMockValueAnimator);
+
+        assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_0));
+        verify(lastEndCallback).run();
+    }
+
+    @Test
     public void testTurnScreenOff_resetsMagnification() {
         register(DISPLAY_0);
         register(DISPLAY_1);
@@ -1043,6 +1137,10 @@
                 ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class);
         verify(mMockValueAnimator).addUpdateListener(listenerArgumentCaptor.capture());
         mTargetAnimationListener = listenerArgumentCaptor.getValue();
+        ArgumentCaptor<ValueAnimator.AnimatorListener> animatorListenerArgumentCaptor =
+                ArgumentCaptor.forClass(ValueAnimator.AnimatorListener.class);
+        verify(mMockValueAnimator).addListener(animatorListenerArgumentCaptor.capture());
+        mStateListener = animatorListenerArgumentCaptor.getValue();
         Mockito.reset(mMockValueAnimator); // Ignore other initialization
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
new file mode 100644
index 0000000..dad360d4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+public class BiometricSchedulerTest {
+
+    private static final String TAG = "BiometricSchedulerTest";
+
+    private BiometricScheduler mScheduler;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private ClientMonitor.LazyDaemon<Object> mLazyDaemon;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */);
+    }
+
+    @Test
+    public void testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash() {
+        final ClientMonitor<Object> client1 = new TestClientMonitor(mContext, mLazyDaemon);
+        final ClientMonitor<Object> client2 = new TestClientMonitor(mContext, mLazyDaemon);
+        mScheduler.scheduleClientMonitor(client1);
+        mScheduler.scheduleClientMonitor(client2);
+
+        client1.mFinishCallback.onClientFinished(client1, true /* success */);
+        client1.mFinishCallback.onClientFinished(client1, true /* success */);
+    }
+
+    private static class TestClientMonitor extends ClientMonitor<Object> {
+
+        public TestClientMonitor(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon) {
+            super(context, lazyDaemon, null /* token */, null /* listener */, 0 /* userId */,
+                    TAG, 0 /* cookie */, 0 /* sensorId */, 0 /* statsModality */,
+                    0 /* statsAction */, 0 /* statsClient */);
+        }
+
+        @Override
+        public void unableToStart() {
+
+        }
+
+        @Override
+        protected void startHalOperation() {
+
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 50086af..870a274 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -144,6 +144,26 @@
     }
 
     @Test
+    public void playbackDevice_updatesActiveSourceState() {
+        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
+                mHdmiControlService);
+        playbackDevice.init();
+        mLocalDevices.add(playbackDevice);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+
+        HdmiCecFeatureAction action = new com.android.server.hdmi.ActiveSourceAction(
+                playbackDevice, ADDR_TV);
+        playbackDevice.addAndStartAction(action);
+        mTestLooper.dispatchAll();
+
+        assertThat(playbackDevice.getActiveSource().logicalAddress).isEqualTo(
+                playbackDevice.mAddress);
+        assertThat(playbackDevice.getActiveSource().physicalAddress).isEqualTo(mPhysicalAddress);
+        assertThat(playbackDevice.mIsActiveSource).isTrue();
+    }
+
+    @Test
     public void audioDevice_sendsActiveSource_noMenuStatus() {
         HdmiCecLocalDeviceAudioSystem audioDevice = new HdmiCecLocalDeviceAudioSystem(
                 mHdmiControlService);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 3205463..960a7ab 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -275,7 +275,6 @@
     }
 
     @Test
-    @Ignore("b/120845532")
     public void handleSetSystemAudioModeOn_audioSystemBroadcast() {
         mHdmiControlService.setSystemAudioActivated(false);
         assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isFalse();
@@ -287,7 +286,6 @@
     }
 
     @Test
-    @Ignore("b/120845532")
     public void handleSetSystemAudioModeOff_audioSystemToPlayback() {
         mHdmiCecLocalDevicePlayback.mService.setSystemAudioActivated(true);
         assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isTrue();
@@ -301,8 +299,7 @@
     }
 
     @Test
-    @Ignore("b/120845532")
-    public void handleSystemAudioModeStatusOn_DirectltToLocalDeviceFromAudioSystem() {
+    public void handleSystemAudioModeStatusOn_DirectlyToLocalDeviceFromAudioSystem() {
         mHdmiControlService.setSystemAudioActivated(false);
         assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isFalse();
         HdmiCecMessage message =
@@ -617,4 +614,19 @@
 
         assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
     }
+
+    @Test
+    public void handleSetStreamPath_afterHotplug_hasCorrectActiveSource() {
+        mHdmiControlService.onHotplug(1, false);
+        mHdmiControlService.onHotplug(1, true);
+
+        HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
+                mPlaybackPhysicalAddress);
+        mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
+        mTestLooper.dispatchAll();
+
+        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+                mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress());
+        assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
index e08eea2..0839273 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -160,7 +160,7 @@
         private val hasPermission: Boolean = false,
         private val overlayableInfo: OverlayableInfo? = null,
         private vararg val packageNames: String = arrayOf("com.test.actor.one")
-    ) : OverlayableInfoCallback {
+    ) : PackageManagerHelper {
 
         override fun getNamedActors() = if (isActor) {
             mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME))
@@ -195,6 +195,14 @@
             }
         }
 
+        override fun getConfigSignaturePackage(): String {
+            throw UnsupportedOperationException()
+        }
+
+        override fun getOverlayPackages(userId: Int): MutableList<PackageInfo> {
+            throw UnsupportedOperationException()
+        }
+
         override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean {
             throw UnsupportedOperationException()
         }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index b7692f9..e281f2b 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -44,9 +44,9 @@
     @Test
     public void testUpdateOverlaysForUser() {
         final OverlayManagerServiceImpl impl = getImpl();
-        addSystemPackage(target(TARGET), USER);
-        addSystemPackage(target("some.other.target"), USER);;
-        addSystemPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(target(TARGET), USER);
+        addPackage(target("some.other.target"), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
 
         // do nothing, expect no change
         final List<String> a = impl.updateOverlaysForUser(USER);
@@ -54,7 +54,7 @@
         assertTrue(a.contains(TARGET));
 
         // upgrade overlay, keep target
-        addSystemPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
 
         final List<String> b = impl.updateOverlaysForUser(USER);
         assertEquals(1, b.size());
@@ -66,7 +66,7 @@
         assertTrue(c.contains(TARGET));
 
         // upgrade overlay, switch to new target
-        addSystemPackage(overlay(OVERLAY, "some.other.target"), USER);
+        addPackage(overlay(OVERLAY, "some.other.target"), USER);
         final List<String> d = impl.updateOverlaysForUser(USER);
         assertEquals(2, d.size());
         assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index f4c5506..c1d862a 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -19,6 +19,7 @@
 import static android.content.om.OverlayInfo.STATE_DISABLED;
 import static android.content.om.OverlayInfo.STATE_ENABLED;
 import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
+import static android.os.OverlayablePolicy.CONFIG_SIGNATURE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -49,6 +50,10 @@
     private static final String OVERLAY3 = OVERLAY + "3";
     private static final int USER3 = USER2 + 1;
 
+    private static final String CONFIG_SIGNATURE_REFERENCE_PKG = "com.dummy.ref";
+    private static final String CERT_CONFIG_OK = "config_certificate_ok";
+    private static final String CERT_CONFIG_NOK = "config_certificate_nok";
+
     @Test
     public void testGetOverlayInfo() {
         installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -204,4 +209,87 @@
         impl.setEnabled(OVERLAY, true, USER);
         assertEquals(0, listener.count);
     }
+
+    @Test
+    public void testConfigSignaturePolicyOk() {
+        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+        reinitializeImpl();
+
+        addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyCertNok() {
+        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+        reinitializeImpl();
+
+        addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyNoConfig() {
+        addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyNoRefPkg() {
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
+
+    @Test
+    public void testConfigSignaturePolicyRefPkgNotSystem() {
+        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+        reinitializeImpl();
+
+        addPackage(app(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+        installNewPackage(target(TARGET), USER);
+        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+        final DummyIdmapDaemon idmapd = getIdmapd();
+        final DummyDeviceState state = getState();
+        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+        DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 733310b..2faf29f 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -27,6 +27,7 @@
 import android.content.om.OverlayableInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -52,6 +53,7 @@
     private DummyPackageManagerHelper mPackageManager;
     private DummyIdmapDaemon mIdmapDaemon;
     private OverlayConfig mOverlayConfig;
+    private String mConfigSignaturePackageName;
 
     @Before
     public void setUp() {
@@ -83,6 +85,18 @@
         return mListener;
     }
 
+    DummyIdmapDaemon getIdmapd() {
+        return mIdmapDaemon;
+    }
+
+    DummyDeviceState getState() {
+        return mState;
+    }
+
+    void setConfigSignaturePackageName(String packageName) {
+        mConfigSignaturePackageName = packageName;
+    }
+
     void assertState(@State int expected, final String overlayPackageName, int userId) {
         final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
         if (info == null) {
@@ -102,9 +116,14 @@
         assertEquals(expected, actual);
     }
 
+    DummyDeviceState.PackageBuilder app(String packageName) {
+        return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
+                null /* targetOverlayableName */, "data");
+    }
+
     DummyDeviceState.PackageBuilder target(String packageName) {
         return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
-                null /* targetOverlayableName */);
+                null /* targetOverlayableName */, "");
     }
 
     DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
@@ -114,10 +133,10 @@
     DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
             String targetOverlayableName) {
         return new DummyDeviceState.PackageBuilder(packageName, targetPackageName,
-                targetOverlayableName);
+                targetOverlayableName, "");
     }
 
-    void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+    void addPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
         mState.add(pkg, userId);
     }
 
@@ -242,15 +261,17 @@
             private String packageName;
             private String targetPackage;
             private String certificate = "[default]";
+            private String partition;
             private int version = 0;
             private ArrayList<String> overlayableNames = new ArrayList<>();
             private String targetOverlayableName;
 
             private PackageBuilder(String packageName, String targetPackage,
-                    String targetOverlayableName) {
+                    String targetOverlayableName, String partition) {
                 this.packageName = packageName;
                 this.targetPackage = targetPackage;
                 this.targetOverlayableName = targetOverlayableName;
+                this.partition = partition;
             }
 
             PackageBuilder setCertificate(String certificate) {
@@ -269,9 +290,19 @@
             }
 
             Package build() {
-                final String apkPath = String.format("%s/%s/base.apk",
-                        targetPackage == null ? "/system/app/:" : "/vendor/overlay/:",
-                        packageName);
+                String path = "";
+                if (TextUtils.isEmpty(partition)) {
+                    if (targetPackage == null) {
+                        path = "/system/app";
+                    } else {
+                        path = "/vendor/overlay";
+                    }
+                } else {
+                    String type = targetPackage == null ? "app" : "overlay";
+                    path = String.format("%s/%s", partition, type);
+                }
+
+                final String apkPath = String.format("%s/%s/base.apk", path, packageName);
                 final Package newPackage = new Package(packageName, targetPackage,
                         targetOverlayableName, version, apkPath, certificate);
                 newPackage.overlayableNames.addAll(overlayableNames);
@@ -302,8 +333,7 @@
         }
     }
 
-    static final class DummyPackageManagerHelper implements PackageManagerHelper,
-            OverlayableInfoCallback {
+    final class DummyPackageManagerHelper implements PackageManagerHelper {
         private final DummyDeviceState mState;
 
         private DummyPackageManagerHelper(DummyDeviceState state) {
@@ -343,6 +373,11 @@
                     .collect(Collectors.toList());
         }
 
+        @Override
+        public @NonNull String getConfigSignaturePackage() {
+            return mConfigSignaturePackageName;
+        }
+
         @Nullable
         @Override
         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 2d9c6ce..f991dff 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -19,7 +19,6 @@
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.empty;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -70,8 +69,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.IntFunction;
-import java.util.stream.Collectors;
 
 @Presubmit
 @RunWith(JUnit4.class)
@@ -805,24 +802,24 @@
                 queriesProviderAppId);
 
         final SparseArray<int[]> systemFilter =
-                appsFilter.getVisibilityWhitelist(system, USER_ARRAY, mExisting);
+                appsFilter.getVisibilityAllowList(system, USER_ARRAY, mExisting);
         assertThat(toList(systemFilter.get(SYSTEM_USER)),
                 contains(seesNothingAppId, hasProviderAppId, queriesProviderAppId));
 
         final SparseArray<int[]> seesNothingFilter =
-                appsFilter.getVisibilityWhitelist(seesNothing, USER_ARRAY, mExisting);
+                appsFilter.getVisibilityAllowList(seesNothing, USER_ARRAY, mExisting);
         assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
                 contains(seesNothingAppId));
         assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
                 contains(seesNothingAppId));
 
         final SparseArray<int[]> hasProviderFilter =
-                appsFilter.getVisibilityWhitelist(hasProvider, USER_ARRAY, mExisting);
+                appsFilter.getVisibilityAllowList(hasProvider, USER_ARRAY, mExisting);
         assertThat(toList(hasProviderFilter.get(SYSTEM_USER)),
                 contains(hasProviderAppId, queriesProviderAppId));
 
         SparseArray<int[]> queriesProviderFilter =
-                appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+                appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
         assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(queriesProviderAppId));
 
@@ -831,7 +828,7 @@
 
         // ensure implicit access is included in the filter
         queriesProviderFilter =
-                appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+                appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
         assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(hasProviderAppId, queriesProviderAppId));
     }
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 70006b4..980772b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -166,6 +166,7 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
 import com.android.server.UiServiceTestCase;
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
@@ -6454,7 +6455,7 @@
     public void testOnUnlockUser() {
         UserInfo ui = new UserInfo();
         ui.id = 10;
-        mService.onUnlockUser(ui);
+        mService.onUserUnlocking(new TargetUser(ui));
         waitForIdle();
 
         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id);
@@ -6464,7 +6465,7 @@
     public void testOnStopUser() {
         UserInfo ui = new UserInfo();
         ui.id = 10;
-        mService.onStopUser(ui);
+        mService.onUserStopping(new TargetUser(ui));
         waitForIdle();
 
         verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index f69d7c3..1eb45d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -59,7 +59,7 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 // TODO(b/144248496): Merge to DisplayContentTests
-public class ActivityDisplayTests extends ActivityTestsBase {
+public class ActivityDisplayTests extends WindowTestsBase {
 
     @Test
     public void testLastFocusedStackIsUpdatedWhenMovingStack() {
@@ -89,9 +89,9 @@
         // Create a pinned stack and move to front.
         final Task pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea()
                 .createStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final Task pinnedTask = new TaskBuilder(mService.mStackSupervisor)
+        final Task pinnedTask = new TaskBuilder(mAtm.mStackSupervisor)
                 .setStack(pinnedStack).build();
-        new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
+        new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
                 .setTask(pinnedTask).build();
         pinnedStack.moveToFront("movePinnedStackToFront");
 
@@ -140,7 +140,7 @@
         // Create a display which supports system decoration and allows reparenting stacks to
         // another display when the display is removed.
         final DisplayContent display = new TestDisplayContent.Builder(
-                mService, 1000, 1500).setSystemDecorations(true).build();
+                mAtm, 1000, 1500).setSystemDecorations(true).build();
         doReturn(false).when(display).shouldDestroyContentOnRemove();
 
         // Put home stack on the display.
@@ -162,9 +162,9 @@
     private Task createFullscreenStackWithSimpleActivityAt(DisplayContent display) {
         final Task fullscreenStack = display.getDefaultTaskDisplayArea().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
+        final Task fullscreenTask = new TaskBuilder(mAtm.mStackSupervisor)
                 .setStack(fullscreenStack).build();
-        new ActivityBuilder(mService).setTask(fullscreenTask).build();
+        new ActivityBuilder(mAtm).setTask(fullscreenTask).build();
         return fullscreenStack;
     }
 
@@ -197,7 +197,7 @@
         assertNull(display.topRunningActivity(true /* considerKeyguardState */));
 
         // Add activity that should be shown on the keyguard.
-        final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService)
+        final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setStack(stack)
                 .setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
@@ -226,7 +226,7 @@
         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         final Task alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(alwaysOnTopStack).build();
         alwaysOnTopStack.setAlwaysOnTop(true);
         taskDisplayArea.positionChildAt(POSITION_TOP, alwaysOnTopStack,
@@ -322,10 +322,10 @@
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
         final Task stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final Task task1 = new TaskBuilder(mService.mStackSupervisor).setStack(stack1).build();
-        final Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(stack2).build();
-        final Task task3 = new TaskBuilder(mService.mStackSupervisor).setStack(stack3).build();
-        final Task task4 = new TaskBuilder(mService.mStackSupervisor).setStack(stack4).build();
+        final Task task1 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack1).build();
+        final Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack2).build();
+        final Task task3 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack3).build();
+        final Task task4 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack4).build();
 
         // Reordering stacks while removing stacks.
         doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index feac6db..46c3e22 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -59,7 +59,7 @@
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
+public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
     private ActivityMetricsLogger mActivityMetricsLogger;
     private ActivityMetricsLogger.LaunchingState mLaunchingState;
     private ActivityMetricsLaunchObserver mLaunchObserver;
@@ -81,11 +81,11 @@
 
         // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
         // This seems to be the easiest way to create an ActivityRecord.
-        mTrampolineActivity = new ActivityBuilder(mService)
+        mTrampolineActivity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TrampolineActivity"))
                 .build();
-        mTopActivity = new ActivityBuilder(mService)
+        mTopActivity = new ActivityBuilder(mAtm)
                 .setTask(mTrampolineActivity.getTask())
                 .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TopActivity"))
                 .build();
@@ -121,7 +121,7 @@
     private <T> T verifyAsync(T mock) {
         // With WindowTestRunner, all test methods are inside WM lock, so we have to unblock any
         // messages that are waiting for the lock.
-        waitHandlerIdle(mService.mH);
+        waitHandlerIdle(mAtm.mH);
         // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
         return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
     }
@@ -192,7 +192,7 @@
         // Suppress resume when creating the record because we want to notify logger manually.
         mSupervisor.beginDeferResume();
         // Create an activity with different process that meets process switch.
-        final ActivityRecord noDrawnActivity = new ActivityBuilder(mService)
+        final ActivityRecord noDrawnActivity = new ActivityBuilder(mAtm)
                 .setTask(mTopActivity.getTask())
                 .setProcessName("other")
                 .build();
@@ -321,7 +321,7 @@
         onActivityLaunched(mTopActivity);
         final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
 
-        final ActivityRecord otherActivity = new ActivityBuilder(mService)
+        final ActivityRecord otherActivity = new ActivityBuilder(mAtm)
                 .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "OtherActivity"))
                 .setCreateTask(true)
                 .build();
@@ -345,7 +345,7 @@
                 .setDisplay(addNewDisplayContentAt(DisplayContent.POSITION_BOTTOM))
                 .setCreateActivity(false)
                 .build();
-        final ActivityRecord activityOnNewDisplay = new ActivityBuilder(mService)
+        final ActivityRecord activityOnNewDisplay = new ActivityBuilder(mAtm)
                 .setStack(stack)
                 .setCreateTask(true)
                 .setProcessName("new")
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 e45ced6..e3830f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -67,7 +67,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -122,7 +121,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class ActivityRecordTests extends ActivityTestsBase {
+public class ActivityRecordTests extends WindowTestsBase {
     private Task mStack;
     private Task mTask;
     private ActivityRecord mActivity;
@@ -133,7 +132,7 @@
         mTask = mStack.getBottomMostTask();
         mActivity = mTask.getTopNonFinishingActivity();
 
-        setBooted(mService);
+        setBooted(mAtm);
     }
 
     @Test
@@ -152,16 +151,16 @@
     public void testStackCleanupOnTaskRemoval() {
         mStack.removeChild(mTask, null /*reason*/);
         // Stack should be gone on task removal.
-        assertNull(mService.mRootWindowContainer.getStack(mStack.mTaskId));
+        assertNull(mAtm.mRootWindowContainer.getStack(mStack.mTaskId));
     }
 
     @Test
     public void testRemoveChildWithOverlayActivity() {
         final ActivityRecord overlayActivity =
-                new ActivityBuilder(mService).setTask(mTask).build();
+                new ActivityBuilder(mAtm).setTask(mTask).build();
         overlayActivity.setTaskOverlay(true);
         final ActivityRecord overlayActivity2 =
-                new ActivityBuilder(mService).setTask(mTask).build();
+                new ActivityBuilder(mAtm).setTask(mTask).build();
         overlayActivity2.setTaskOverlay(true);
 
         mTask.removeChild(overlayActivity2, "test");
@@ -170,7 +169,7 @@
 
     @Test
     public void testNoCleanupMovingActivityInSameStack() {
-        final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+        final Task newTask = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
         mActivity.reparent(newTask, 0, null /*reason*/);
         verify(mStack, times(0)).cleanUpActivityReferences(any());
     }
@@ -213,7 +212,7 @@
         // Make sure the state does not change if we are not the current top activity.
         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
 
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         mStack.mTranslucentActivityWaiting = topActivity;
         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
         assertTrue(mActivity.isState(STARTED));
@@ -231,8 +230,8 @@
 
     @Test
     public void testCanBeLaunchedOnDisplay() {
-        mService.mSupportsMultiWindow = true;
-        final ActivityRecord activity = new ActivityBuilder(mService).build();
+        mAtm.mSupportsMultiWindow = true;
+        final ActivityRecord activity = new ActivityBuilder(mAtm).build();
 
         // An activity can be launched on default display.
         assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
@@ -251,7 +250,7 @@
 
         // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
         // Pending options should be cleared for both ActivityRecords
-        ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
+        ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(mTask).build();
         activity2.updateOptionsLocked(activityOptions);
         mActivity.updateOptionsLocked(activityOptions);
         mActivity.applyOptionsLocked();
@@ -260,8 +259,8 @@
 
         // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
         // Pending options should be cleared for only ActivityRecord that was applied
-        Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
-        activity2 = new ActivityBuilder(mService).setTask(task2).build();
+        Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
+        activity2 = new ActivityBuilder(mAtm).setTask(task2).build();
         activity2.updateOptionsLocked(activityOptions);
         mActivity.updateOptionsLocked(activityOptions);
         mActivity.applyOptionsLocked();
@@ -362,7 +361,7 @@
 
     @Test
     public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
-        mActivity = new ActivityBuilder(mService)
+        mActivity = new ActivityBuilder(mAtm)
                 .setTask(mTask)
                 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
                 .build();
@@ -405,7 +404,7 @@
 
         final ActivityConfigurationChangeItem expected =
                 ActivityConfigurationChangeItem.obtain(newConfig);
-        verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
+        verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
                 eq(mActivity.appToken), eq(expected));
     }
 
@@ -500,9 +499,9 @@
 
     @Test
     public void testShouldMakeActive_nonTopVisible() {
-        ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        ActivityRecord finishingActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         finishingActivity.finishing = true;
-        ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         mActivity.setState(Task.ActivityState.STOPPED, "Testing");
 
         assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
@@ -528,7 +527,7 @@
         mActivity.setState(Task.ActivityState.STOPPED, "Testing");
         spyOn(mStack);
 
-        ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
         topActivity.finishing = true;
 
@@ -539,7 +538,7 @@
 
     @Test
     public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
-        mActivity = new ActivityBuilder(mService)
+        mActivity = new ActivityBuilder(mAtm)
                 .setTask(mTask)
                 .setLaunchTaskBehind(true)
                 .setConfigChanges(CONFIG_ORIENTATION)
@@ -574,7 +573,7 @@
 
             final ActivityConfigurationChangeItem expected =
                     ActivityConfigurationChangeItem.obtain(newConfig);
-            verify(mService.getLifecycleManager()).scheduleTransaction(
+            verify(mAtm.getLifecycleManager()).scheduleTransaction(
                     eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
         } finally {
             stack.getDisplayArea().removeChild(stack);
@@ -583,7 +582,7 @@
 
     @Test
     public void testShouldStartWhenMakeClientActive() {
-        ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.setOccludesParent(false);
         mActivity.setState(Task.ActivityState.STOPPED, "Testing");
         mActivity.setVisibility(true);
@@ -621,7 +620,7 @@
     public void testCanLaunchHomeActivityFromChooser() {
         ComponentName chooserComponent = ComponentName.unflattenFromString(
                 Resources.getSystem().getString(R.string.config_chooserActivity));
-        ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
+        ActivityRecord chooserActivity = new ActivityBuilder(mAtm).setComponent(
                 chooserComponent).build();
         assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
     }
@@ -736,7 +735,7 @@
 
         // Put a visible activity on top, so the finishing activity doesn't have to wait until the
         // next activity reports idle to destroy it.
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.setState(RESUMED, "test");
@@ -914,7 +913,7 @@
     public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
         // Put an activity on top of test activity to make it invisible and prevent us from
         // accidentally resuming the topmost one again.
-        new ActivityBuilder(mService).build();
+        new ActivityBuilder(mAtm).build();
         mActivity.mVisibleRequested = false;
         mActivity.setState(STOPPED, "test");
 
@@ -992,7 +991,7 @@
      */
     @Test
     public void testCompleteFinishing_waitForNextVisible() {
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.finishing = true;
@@ -1017,7 +1016,7 @@
      */
     @Test
     public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.mVisibleRequested = false;
         topActivity.nowVisible = false;
         topActivity.finishing = true;
@@ -1039,7 +1038,7 @@
      */
     @Test
     public void testCompleteFinishing_waitForIdle() {
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.finishing = true;
@@ -1060,7 +1059,7 @@
      */
     @Test
     public void testCompleteFinishing_noWaitForNextVisible_stopped() {
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.mVisibleRequested = false;
         topActivity.nowVisible = false;
         topActivity.finishing = true;
@@ -1081,7 +1080,7 @@
      */
     @Test
     public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.finishing = true;
@@ -1114,7 +1113,7 @@
         // Make keyguard locked and set the top activity show-when-locked.
         KeyguardController keyguardController = mActivity.mStackSupervisor.getKeyguardController();
         doReturn(true).when(keyguardController).isKeyguardLocked();
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.setState(RESUMED, "true");
@@ -1143,18 +1142,18 @@
      */
     @Test
     public void testCompleteFinishing_ensureActivitiesVisible() {
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         firstActivity.mVisibleRequested = false;
         firstActivity.nowVisible = false;
         firstActivity.setState(STOPPED, "true");
 
-        final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         secondActivity.mVisibleRequested = true;
         secondActivity.nowVisible = true;
         secondActivity.setState(PAUSED, "true");
 
         final ActivityRecord translucentActivity =
-                new ActivityBuilder(mService).setTask(mTask).build();
+                new ActivityBuilder(mAtm).setTask(mTask).build();
         translucentActivity.mVisibleRequested = true;
         translucentActivity.nowVisible = true;
         translucentActivity.setState(RESUMED, "true");
@@ -1327,12 +1326,15 @@
     public void testRemoveFromHistory() {
         final Task stack = mActivity.getRootTask();
         final Task task = mActivity.getTask();
+        final WindowProcessController wpc = mActivity.app;
+        assertTrue(wpc.hasActivities());
 
         mActivity.removeFromHistory("test");
 
         assertEquals(DESTROYED, mActivity.getState());
         assertNull(mActivity.app);
         assertNull(mActivity.getTask());
+        assertFalse(wpc.hasActivities());
         assertEquals(0, task.getChildCount());
         assertEquals(task.getRootTask(), task);
         assertEquals(0, stack.getChildCount());
@@ -1393,7 +1395,7 @@
 
         final Task firstTaskRecord = mActivity.getTask();
         final ActivityRecord secondActivityRecord =
-                new ActivityBuilder(mService).setTask(firstTaskRecord).setUseProcess(wpc).build();
+                new ActivityBuilder(mAtm).setTask(firstTaskRecord).setUseProcess(wpc).build();
 
         assertTrue(wpc.registeredForActivityConfigChanges());
         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
@@ -1406,7 +1408,7 @@
         assertTrue(wpc.registeredForActivityConfigChanges());
 
         final ActivityRecord secondActivityRecord =
-                new ActivityBuilder(mService).setTask(mTask).setUseProcess(wpc).build();
+                new ActivityBuilder(mAtm).setTask(mTask).setUseProcess(wpc).build();
 
         assertTrue(wpc.registeredForActivityConfigChanges());
         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
@@ -1502,7 +1504,7 @@
                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
         params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
         final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
-                mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
+                mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
         mActivity.addWindow(w);
 
         // Assume the activity is launching in different rotation, and there was an available
@@ -1523,7 +1525,7 @@
                     any() /* outContentInsets */, any() /* outStableInsets */,
                     any() /* outDisplayCutout */, any() /* outInputChannel */,
                     any() /* outInsetsState */, any() /* outActiveControls */);
-            TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
+            TaskSnapshotSurface.create(mAtm.mWindowManager, mActivity, snapshot);
         } catch (RemoteException ignored) {
         } finally {
             reset(session);
@@ -1599,7 +1601,7 @@
         final Configuration initialConf =
                 new Configuration(mActivity.getMergedOverrideConfiguration());
         final Task initialTask = mActivity.getTask();
-        final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(initialTask)
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(initialTask)
                 .setUseProcess(wpc).build();
 
         assertTrue(wpc.registeredForActivityConfigChanges());
@@ -1693,12 +1695,12 @@
         if (defaultDisplay) {
             display = mRootWindowContainer.getDefaultDisplay();
         } else {
-            display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300)
+            display = new TestDisplayContent.Builder(mAtm, 2000, 1000).setDensityDpi(300)
                     .setPosition(DisplayContent.POSITION_TOP).build();
         }
         final Task stack = display.getDefaultTaskDisplayArea()
                 .createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
-        return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
+        return new ActivityBuilder(mAtm).setTask(task).setUseProcess(process).build();
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 197c89a..addf1ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -55,7 +55,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class ActivityStackSupervisorTests extends ActivityTestsBase {
+public class ActivityStackSupervisorTests extends WindowTestsBase {
     private Task mFullscreenStack;
 
     @Before
@@ -69,7 +69,7 @@
      */
     @Test
     public void testStoppingActivityRemovedWhenResumed() {
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
         mSupervisor.mStoppingActivities.add(firstActivity);
 
@@ -83,7 +83,7 @@
      */
     @Test
     public void testReportWaitingActivityLaunchedIfNeeded() {
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
 
         final WaitResult taskToFrontWait = new WaitResult();
@@ -121,7 +121,7 @@
         task.setResizeMode(unresizableActivity.info.resizeMode);
 
         final TaskChangeNotificationController taskChangeNotifier =
-                mService.getTaskChangeNotificationController();
+                mAtm.getTaskChangeNotificationController();
         spyOn(taskChangeNotifier);
 
         mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(),
@@ -133,7 +133,7 @@
         reset(taskChangeNotifier);
 
         // Put a resizable activity on top of the unresizable task.
-        final ActivityRecord resizableActivity = new ActivityBuilder(mService)
+        final ActivityRecord resizableActivity = new ActivityBuilder(mAtm)
                 .setTask(task).build();
         resizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
 
@@ -150,24 +150,24 @@
      */
     @Test
     public void testNotifyTaskFocusChanged() {
-        final ActivityRecord fullScreenActivityA = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord fullScreenActivityA = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
         final Task taskA = fullScreenActivityA.getTask();
 
         final TaskChangeNotificationController taskChangeNotifier =
-                mService.getTaskChangeNotificationController();
+                mAtm.getTaskChangeNotificationController();
         spyOn(taskChangeNotifier);
 
-        mService.setResumedActivityUncheckLocked(fullScreenActivityA, "resumeA");
+        mAtm.setResumedActivityUncheckLocked(fullScreenActivityA, "resumeA");
         verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskA.mTaskId) /* taskId */,
                 eq(true) /* focused */);
         reset(taskChangeNotifier);
 
-        final ActivityRecord fullScreenActivityB = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord fullScreenActivityB = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
         final Task taskB = fullScreenActivityB.getTask();
 
-        mService.setResumedActivityUncheckLocked(fullScreenActivityB, "resumeB");
+        mAtm.setResumedActivityUncheckLocked(fullScreenActivityB, "resumeB");
         verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskA.mTaskId) /* taskId */,
                 eq(false) /* focused */);
         verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskB.mTaskId) /* taskId */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 775df74..e2948a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -89,7 +89,7 @@
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class ActivityStackTests extends ActivityTestsBase {
+public class ActivityStackTests extends WindowTestsBase {
     private TaskDisplayArea mDefaultTaskDisplayArea;
     private Task mStack;
     private Task mTask;
@@ -105,7 +105,7 @@
 
     @Test
     public void testResumedActivity() {
-        final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
         assertNull(mStack.getResumedActivity());
         r.setState(RESUMED, "testResumedActivity");
         assertEquals(r, mStack.getResumedActivity());
@@ -115,7 +115,7 @@
 
     @Test
     public void testResumedActivityFromTaskReparenting() {
-        final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
         // Ensure moving task between two stacks updates resumed activity
         r.setState(RESUMED, "testResumedActivityFromTaskReparenting");
         assertEquals(r, mStack.getResumedActivity());
@@ -133,7 +133,7 @@
 
     @Test
     public void testResumedActivityFromActivityReparenting() {
-        final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
         // Ensure moving task between two stacks updates resumed activity
         r.setState(RESUMED, "testResumedActivityFromActivityReparenting");
         assertEquals(r, mStack.getResumedActivity());
@@ -149,7 +149,7 @@
 
     @Test
     public void testPrimarySplitScreenMoveToBack() {
-        TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+        TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
         // We're testing an edge case here where we have primary + fullscreen rather than secondary.
         organizer.setMoveToSecondaryOnEnter(false);
 
@@ -177,7 +177,7 @@
 
     @Test
     public void testMoveToPrimarySplitScreenThenMoveToBack() {
-        TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+        TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
         // This time, start with a fullscreen activitystack
         final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack(
                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -202,7 +202,7 @@
 
     @Test
     public void testSplitScreenMoveToBack() {
-        TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+        TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
         // Set up split-screen with primary on top and secondary containing the home task below
         // another stack.
         final Task primaryTask = mDefaultTaskDisplayArea.createStack(
@@ -241,12 +241,12 @@
     @Test
     public void testRemoveOrganizedTask_UpdateStackReference() {
         final Task rootHomeTask = mDefaultTaskDisplayArea.getRootHomeTask();
-        final ActivityRecord homeActivity = new ActivityBuilder(mService)
+        final ActivityRecord homeActivity = new ActivityBuilder(mAtm)
                 .setStack(rootHomeTask)
                 .setCreateTask(true)
                 .build();
         final Task secondaryStack = (Task) WindowContainer.fromBinder(
-                mService.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(),
+                mAtm.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(),
                         WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token.asBinder());
 
         rootHomeTask.reparent(secondaryStack, POSITION_TOP);
@@ -292,7 +292,7 @@
 
     @Test
     public void testStopActivityWhenActivityDestroyed() {
-        final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
         r.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
         mStack.moveToFront("testStopActivityWithDestroy");
         r.stopIfPossible();
@@ -302,14 +302,14 @@
 
     @Test
     public void testFindTaskWithOverlay() {
-        final ActivityRecord r = new ActivityBuilder(mService)
+        final ActivityRecord r = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setStack(mStack)
                 .setUid(0)
                 .build();
         final Task task = r.getTask();
         // Overlay must be for a different user to prevent recognizing a matching top activity
-        final ActivityRecord taskOverlay = new ActivityBuilder(mService).setTask(task)
+        final ActivityRecord taskOverlay = new ActivityBuilder(mAtm).setTask(task)
                 .setUid(UserHandle.PER_USER_RANGE * 2).build();
         taskOverlay.setTaskOverlay(true);
 
@@ -330,21 +330,21 @@
                 targetActivity);
         final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME,
                 aliasActivity);
-        final Task task = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+        final Task task = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
         task.origActivity = alias;
         task.realActivity = target;
-        new ActivityBuilder(mService).setComponent(target).setTask(task).setTargetActivity(
+        new ActivityBuilder(mAtm).setComponent(target).setTask(task).setTargetActivity(
                 targetActivity).build();
 
         // Using target activity to find task.
-        final ActivityRecord r1 = new ActivityBuilder(mService).setComponent(
+        final ActivityRecord r1 = new ActivityBuilder(mAtm).setComponent(
                 target).setTargetActivity(targetActivity).build();
         RootWindowContainer.FindTaskResult result = new RootWindowContainer.FindTaskResult();
         result.process(r1, mStack);
         assertThat(result.mRecord).isNotNull();
 
         // Using alias activity to find task.
-        final ActivityRecord r2 = new ActivityBuilder(mService).setComponent(
+        final ActivityRecord r2 = new ActivityBuilder(mAtm).setComponent(
                 alias).setTargetActivity(targetActivity).build();
         result = new RootWindowContainer.FindTaskResult();
         result.process(r2, mStack);
@@ -377,7 +377,7 @@
         final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         // Add an activity to the pinned stack so it isn't considered empty for visibility check.
-        final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+        final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setStack(pinnedStack)
                 .build();
@@ -676,7 +676,7 @@
         assertEquals(STACK_VISIBILITY_VISIBLE,
                 translucentStack.getVisibility(null /* starting */));
         // Add an activity to the pinned stack so it isn't considered empty for visibility check.
-        final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
+        final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setStack(pinnedStack)
                 .build();
@@ -689,7 +689,7 @@
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
         ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
         if (topRunningHomeActivity == null) {
-            topRunningHomeActivity = new ActivityBuilder(mService)
+            topRunningHomeActivity = new ActivityBuilder(mAtm)
                     .setStack(homeStack)
                     .setCreateTask(true)
                     .build();
@@ -721,12 +721,12 @@
         final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
 
-        final ActivityRecord firstActivity = new ActivityBuilder(mService)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
                     .setStack(homeStack)
                     .setCreateTask(true)
                     .build();
         final Task task = firstActivity.getTask();
-        final ActivityRecord secondActivity = new ActivityBuilder(mService)
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
                 .setTask(task)
                 .build();
 
@@ -991,7 +991,6 @@
             TaskDisplayArea taskDisplayArea, int windowingMode, int activityType, boolean onTop) {
         final Task task;
         if (activityType == ACTIVITY_TYPE_HOME) {
-            // Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
             task = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
             mDefaultTaskDisplayArea.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, task,
                     false /* includingParents */);
@@ -1009,8 +1008,8 @@
 
     @Test
     public void testFinishDisabledPackageActivities_FinishAliveActivities() {
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         firstActivity.setState(STOPPED, "testFinishDisabledPackageActivities");
         secondActivity.setState(RESUMED, "testFinishDisabledPackageActivities");
         mStack.mResumedActivity = secondActivity;
@@ -1029,10 +1028,10 @@
 
     @Test
     public void testFinishDisabledPackageActivities_RemoveNonAliveActivities() {
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
 
         // The overlay activity is not in the disabled package but it is in the same task.
-        final ActivityRecord overlayActivity = new ActivityBuilder(mService).setTask(mTask)
+        final ActivityRecord overlayActivity = new ActivityBuilder(mAtm).setTask(mTask)
                 .setComponent(new ComponentName("package.overlay", ".OverlayActivity")).build();
         // If the task only remains overlay activity, the task should also be removed.
         // See {@link ActivityStack#removeFromHistory}.
@@ -1058,8 +1057,8 @@
 
     @Test
     public void testHandleAppDied() {
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
 
         // Making the first activity a task overlay means it will be removed from the task's
         // activities as well once second activity is removed as handleAppDied processes the
@@ -1072,7 +1071,7 @@
 
         assertEquals(2, mTask.getChildCount());
 
-        mRootWindowContainer.handleAppDied(secondActivity.app);
+        secondActivity.app.handleAppDied();
 
         assertFalse(mTask.hasChild());
         assertFalse(mStack.hasChild());
@@ -1080,13 +1079,13 @@
 
     @Test
     public void testHandleAppDied_RelaunchesAfterCrashDuringWindowingModeResize() {
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
 
         activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
         activity.launchCount = 1;
         activity.setSavedState(null /* savedState */);
 
-        mRootWindowContainer.handleAppDied(activity.app);
+        activity.app.handleAppDied();
 
         assertEquals(1, mTask.getChildCount());
         assertEquals(1, mStack.getChildCount());
@@ -1094,13 +1093,13 @@
 
     @Test
     public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringWindowingModeResize() {
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
 
         activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
         activity.launchCount = 3;
         activity.setSavedState(null /* savedState */);
 
-        mRootWindowContainer.handleAppDied(activity.app);
+        activity.app.handleAppDied();
 
         assertFalse(mTask.hasChild());
         assertFalse(mStack.hasChild());
@@ -1108,13 +1107,13 @@
 
     @Test
     public void testHandleAppDied_RelaunchesAfterCrashDuringFreeResize() {
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
 
         activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
         activity.launchCount = 1;
         activity.setSavedState(null /* savedState */);
 
-        mRootWindowContainer.handleAppDied(activity.app);
+        activity.app.handleAppDied();
 
         assertEquals(1, mTask.getChildCount());
         assertEquals(1, mStack.getChildCount());
@@ -1122,13 +1121,13 @@
 
     @Test
     public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringFreeResize() {
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(mTask).build();
 
         activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
         activity.launchCount = 3;
         activity.setSavedState(null /* savedState */);
 
-        mRootWindowContainer.handleAppDied(activity.app);
+        activity.app.handleAppDied();
 
         assertFalse(mTask.hasChild());
         assertFalse(mStack.hasChild());
@@ -1136,11 +1135,11 @@
 
     @Test
     public void testCompletePauseOnResumeWhilePausingActivity() {
-        final ActivityRecord bottomActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord bottomActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         doReturn(true).when(bottomActivity).attachedToProcess();
         mStack.mPausingActivity = null;
         mStack.mResumedActivity = bottomActivity;
-        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
         topActivity.info.flags |= FLAG_RESUME_WHILE_PAUSING;
 
         mStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, topActivity);
@@ -1154,7 +1153,7 @@
 
         ActivityRecord activity = homeStack.topRunningActivity();
         if (activity == null) {
-            activity = new ActivityBuilder(mService)
+            activity = new ActivityBuilder(mAtm)
                     .setStack(homeStack)
                     .setCreateTask(true)
                     .build();
@@ -1265,13 +1264,13 @@
     public void testNavigateUpTo() {
         final ActivityStartController controller = mock(ActivityStartController.class);
         final ActivityStarter starter = new ActivityStarter(controller,
-                mService, mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
-        doReturn(controller).when(mService).getActivityStartController();
+                mAtm, mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class));
+        doReturn(controller).when(mAtm).getActivityStartController();
         spyOn(starter);
         doReturn(ActivityManager.START_SUCCESS).when(starter).execute();
 
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(mTask).build();
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(mTask)
                 .setUid(firstActivity.getUid() + 1).build();
         doReturn(starter).when(controller).obtainStarter(eq(firstActivity.intent), anyString());
 
@@ -1297,7 +1296,7 @@
     @Test
     public void testShouldUpRecreateTaskLockedWithCorrectAffinityFormat() {
         final String affinity = "affinity";
-        final ActivityRecord activity = new ActivityBuilder(mService).setAffinity(affinity)
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setAffinity(affinity)
                 .setUid(Binder.getCallingUid()).setCreateTask(true).build();
         activity.getTask().affinity = activity.taskAffinity;
 
@@ -1307,7 +1306,7 @@
     @Test
     public void testShouldUpRecreateTaskLockedWithWrongAffinityFormat() {
         final String affinity = "affinity";
-        final ActivityRecord activity = new ActivityBuilder(mService).setAffinity(affinity)
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setAffinity(affinity)
                 .setUid(Binder.getCallingUid()).setCreateTask(true).build();
         activity.getTask().affinity = activity.taskAffinity;
         final String fakeAffinity = activity.getUid() + activity.taskAffinity;
@@ -1318,12 +1317,12 @@
     @Test
     public void testResetTaskWithFinishingActivities() {
         final ActivityRecord taskTop =
-                new ActivityBuilder(mService).setStack(mStack).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setStack(mStack).setCreateTask(true).build();
         // Make all activities in the task are finishing to simulate Task#getTopActivity
         // returns null.
         taskTop.finishing = true;
 
-        final ActivityRecord newR = new ActivityBuilder(mService).build();
+        final ActivityRecord newR = new ActivityBuilder(mAtm).build();
         final ActivityRecord result = mStack.resetTaskIfNeeded(taskTop, newR);
         assertThat(result).isEqualTo(taskTop);
     }
@@ -1333,9 +1332,9 @@
         final ArrayList<ActivityRecord> occludedActivities = new ArrayList<>();
         final Consumer<ActivityRecord> handleOccludedActivity = occludedActivities::add;
         final ActivityRecord bottomActivity =
-                new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+                new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
         final ActivityRecord topActivity =
-                new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+                new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
         // Top activity occludes bottom activity.
         doReturn(true).when(mStack).shouldBeVisible(any());
         assertTrue(topActivity.shouldBeVisible());
@@ -1354,7 +1353,7 @@
 
         // A finishing activity should not occlude other activities behind.
         final ActivityRecord finishingActivity =
-                new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+                new ActivityBuilder(mAtm).setStack(mStack).setTask(mTask).build();
         finishingActivity.finishing = true;
         doCallRealMethod().when(finishingActivity).occludesParent();
         assertTrue(topActivity.shouldBeVisible());
@@ -1376,9 +1375,9 @@
         final ActivityRecord[] activities = new ActivityRecord[2];
         mSupervisor.beginDeferResume();
         for (int i = 0; i < activities.length; i++) {
-            final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+            final ActivityRecord r = new ActivityBuilder(mAtm).setTask(mTask).build();
             activities[i] = r;
-            doReturn(null).when(mService).getProcessController(
+            doReturn(null).when(mAtm).getProcessController(
                     eq(r.processName), eq(r.info.applicationInfo.uid));
             r.setState(Task.ActivityState.INITIALIZING, "test");
             // Ensure precondition that the activity is opaque.
@@ -1388,7 +1387,7 @@
         }
         mSupervisor.endDeferResume();
 
-        setBooted(mService);
+        setBooted(mAtm);
         // 2 activities are started while keyguard is locked, so they are waiting to be resolved.
         assertFalse(unknownAppVisibilityController.allResolved());
 
@@ -1405,8 +1404,8 @@
     @Test
     public void testNonTopVisibleActivityNotResume() {
         final ActivityRecord nonTopVisibleActivity =
-                new ActivityBuilder(mService).setTask(mTask).build();
-        new ActivityBuilder(mService).setTask(mTask).build();
+                new ActivityBuilder(mAtm).setTask(mTask).build();
+        new ActivityBuilder(mAtm).setTask(mTask).build();
         doReturn(false).when(nonTopVisibleActivity).attachedToProcess();
         doReturn(true).when(nonTopVisibleActivity).shouldBeVisible(anyBoolean(), anyBoolean());
         doNothing().when(mSupervisor).startSpecificActivity(any(), anyBoolean(),
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index c9a9279..55afc70 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -51,7 +51,7 @@
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class ActivityStartControllerTests extends ActivityTestsBase {
+public class ActivityStartControllerTests extends WindowTestsBase {
     private ActivityStartController mController;
     private Factory mFactory;
     private ActivityStarter mStarter;
@@ -59,9 +59,9 @@
     @Before
     public void setUp() throws Exception {
         mFactory = mock(Factory.class);
-        mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
-        mStarter = spy(new ActivityStarter(mController, mService,
-                mService.mStackSupervisor, mock(ActivityStartInterceptor.class)));
+        mController = new ActivityStartController(mAtm, mAtm.mStackSupervisor, mFactory);
+        mStarter = spy(new ActivityStarter(mController, mAtm,
+                mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class)));
         doReturn(mStarter).when(mFactory).obtain();
     }
 
@@ -72,15 +72,15 @@
     public void testPendingActivityLaunches() {
         final Random random = new Random();
 
-        final ActivityRecord activity = new ActivityBuilder(mService).build();
-        final ActivityRecord source = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm).build();
+        final ActivityRecord source = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .build();
         final int startFlags = random.nextInt();
-        final Task stack = mService.mRootWindowContainer.getDefaultTaskDisplayArea()
+        final Task stack = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea()
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final WindowProcessController wpc = new WindowProcessController(mService,
-                mService.mContext.getApplicationInfo(), "name", 12345,
+        final WindowProcessController wpc = new WindowProcessController(mAtm,
+                mAtm.mContext.getApplicationInfo(), "name", 12345,
                 UserHandle.getUserId(12345), mock(Object.class),
                 mock(WindowProcessListener.class));
         wpc.setThread(mock(IApplicationThread.class));
@@ -101,8 +101,8 @@
     @Test
     public void testRecycling() {
         final Intent intent = new Intent();
-        final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
-                mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
+        final ActivityStarter optionStarter = new ActivityStarter(mController, mAtm,
+                mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class));
         optionStarter
                 .setIntent(intent)
                 .setReason("Test")
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 d07000f..e5c9ecc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -100,7 +100,7 @@
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class ActivityStarterTests extends ActivityTestsBase {
+public class ActivityStarterTests extends WindowTestsBase {
     private ActivityStartController mController;
     private ActivityMetricsLogger mActivityMetricsLogger;
     private PackageManagerInternal mMockPackageManager;
@@ -187,7 +187,7 @@
      */
     private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
             int expectedResult) {
-        final ActivityTaskManagerService service = mService;
+        final ActivityTaskManagerService service = mAtm;
         final IPackageManager packageManager = mock(IPackageManager.class);
         final ActivityStartController controller = mock(ActivityStartController.class);
 
@@ -283,8 +283,8 @@
 
         // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
         if (expectedResult != START_SUCCESS) {
-            final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
-                    mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
+            final ActivityStarter optionStarter = new ActivityStarter(mController, mAtm,
+                    mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class));
             final ActivityOptions options = spy(ActivityOptions.makeBasic());
 
             final int optionResult = optionStarter.setCaller(caller)
@@ -338,7 +338,7 @@
                 invocation -> {
                     throw new RuntimeException("Not stubbed");
                 });
-        doReturn(mMockPackageManager).when(mService).getPackageManagerInternalLocked();
+        doReturn(mMockPackageManager).when(mAtm).getPackageManagerInternalLocked();
         doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
         doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
                 anyInt(), anyBoolean(), anyInt());
@@ -359,8 +359,8 @@
         info.applicationInfo = new ApplicationInfo();
         info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
 
-        return new ActivityStarter(mController, mService,
-                mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
+        return new ActivityStarter(mController, mAtm,
+                mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class))
                 .setIntent(intent)
                 .setActivityInfo(info);
     }
@@ -373,7 +373,7 @@
     public void testCreateTaskLayout() {
         // modifier for validating passed values.
         final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
-        mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
+        mAtm.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
 
         // add custom values to activity info to make unique.
         final ActivityInfo info = new ActivityInfo();
@@ -414,9 +414,9 @@
         final ActivityStarter starter = prepareStarter(
                 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
         final ActivityRecord splitPrimaryFocusActivity =
-                new ActivityBuilder(mService).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord splitSecondReusableActivity =
-                new ActivityBuilder(mService).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setCreateTask(true).build();
         splitPrimaryFocusActivity.getRootTask()
                 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         splitSecondReusableActivity.getRootTask()
@@ -443,11 +443,11 @@
         final ActivityStarter starter = prepareStarter(
                 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
         final ActivityRecord splitSecondReusableActivity =
-                new ActivityBuilder(mService).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord splitSecondTopActivity =
-                new ActivityBuilder(mService).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord splitPrimaryFocusActivity =
-                new ActivityBuilder(mService).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setCreateTask(true).build();
         splitPrimaryFocusActivity.getRootTask()
                 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         splitSecondReusableActivity.getRootTask()
@@ -475,13 +475,13 @@
      */
     @Test
     public void testTaskModeViolation() {
-        final DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
+        final DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
         display.removeAllTasks();
         assertNoTasks(display);
 
         final ActivityStarter starter = prepareStarter(0);
 
-        final LockTaskController lockTaskController = mService.getLockTaskController();
+        final LockTaskController lockTaskController = mAtm.getLockTaskController();
         doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
 
         final int result = starter.setReason("testTaskModeViolation").execute();
@@ -504,8 +504,8 @@
      */
     @Test
     public void testActivityStartsLogging_noLoggingWhenDisabled() {
-        doReturn(false).when(mService).isActivityStartsLoggingEnabled();
-        doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
+        doReturn(false).when(mAtm).isActivityStartsLoggingEnabled();
+        doReturn(mActivityMetricsLogger).when(mAtm.mStackSupervisor).getActivityMetricsLogger();
 
         ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
         starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
@@ -521,8 +521,8 @@
     @Test
     public void testActivityStartsLogging_logsWhenEnabled() {
         // note: conveniently this package doesn't have any activity visible
-        doReturn(true).when(mService).isActivityStartsLoggingEnabled();
-        doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
+        doReturn(true).when(mAtm).isActivityStartsLoggingEnabled();
+        doReturn(mActivityMetricsLogger).when(mAtm.mStackSupervisor).getActivityMetricsLogger();
 
         ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
                 .setCallingUid(FAKE_CALLING_UID)
@@ -544,7 +544,7 @@
      */
     @Test
     public void testBackgroundActivityStartsAllowed_noStartsAborted() {
-        doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
+        doReturn(true).when(mAtm).isBackgroundActivityStartsEnabled();
 
         runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
@@ -558,7 +558,7 @@
      */
     @Test
     public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
-        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
+        doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
 
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_unsupportedUsecase_aborted", true,
@@ -589,7 +589,7 @@
      */
     @Test
     public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
-        doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
+        doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
 
         runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
                 Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
@@ -644,13 +644,13 @@
             boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
             boolean isCallingUidDeviceOwner) {
         // window visibility
-        doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
+        doReturn(callingUidHasVisibleWindow).when(mAtm.mWindowManager.mRoot)
                 .isAnyNonToastWindowVisibleForUid(callingUid);
-        doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
+        doReturn(realCallingUidHasVisibleWindow).when(mAtm.mWindowManager.mRoot)
                 .isAnyNonToastWindowVisibleForUid(realCallingUid);
         // process importance
-        doReturn(callingUidProcState).when(mService).getUidState(callingUid);
-        doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
+        doReturn(callingUidProcState).when(mAtm).getUidState(callingUid);
+        doReturn(realCallingUidProcState).when(mAtm).getUidState(realCallingUid);
         // foreground activities
         final IApplicationThread caller = mock(IApplicationThread.class);
         final WindowProcessListener listener = mock(WindowProcessListener.class);
@@ -658,12 +658,12 @@
         ai.uid = callingUid;
         ai.packageName = "com.android.test.package";
         final WindowProcessController callerApp =
-                new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
+                new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener);
         callerApp.setHasForegroundActivities(hasForegroundActivities);
-        doReturn(callerApp).when(mService).getProcessController(caller);
+        doReturn(callerApp).when(mAtm).getProcessController(caller);
         // caller is recents
         RecentTasks recentTasks = mock(RecentTasks.class);
-        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        mAtm.mStackSupervisor.setRecentTasks(recentTasks);
         doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
         // caller is temp allowed
         if (callerIsTempAllowed) {
@@ -673,7 +673,7 @@
         callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
                 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
         // callingUid is the device owner
-        doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
+        doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid);
 
         final ActivityOptions options = spy(ActivityOptions.makeBasic());
         ActivityRecord[] outActivity = new ActivityRecord[1];
@@ -706,14 +706,14 @@
     @Test
     public void testBringTaskToFrontWhenFocusedStackIsFinising() {
         // Put 2 tasks in the same stack (simulate the behavior of home stack).
-        final ActivityRecord activity = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true).build();
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setStack(activity.getRootTask())
                 .setCreateTask(true).build();
 
         // Create a top finishing activity.
-        final ActivityRecord finishingTopActivity = new ActivityBuilder(mService)
+        final ActivityRecord finishingTopActivity = new ActivityBuilder(mAtm)
                 .setCreateTask(true).build();
         finishingTopActivity.getRootTask().moveToFront("finishingTopActivity");
 
@@ -741,7 +741,7 @@
 
         // Create a secondary display at bottom.
         final TestDisplayContent secondaryDisplay =
-                new TestDisplayContent.Builder(mService, 1000, 1500)
+                new TestDisplayContent.Builder(mAtm, 1000, 1500)
                         .setPosition(POSITION_BOTTOM).build();
         final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
         final Task stack = secondaryTaskContainer.createStack(
@@ -751,7 +751,7 @@
         final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
 
         // Put an activity on default display as the top focused activity.
-        new ActivityBuilder(mService).setCreateTask(true).build();
+        new ActivityBuilder(mAtm).setCreateTask(true).build();
 
         // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
         // on secondary display.
@@ -781,7 +781,7 @@
 
         // Create a secondary display with an activity.
         final TestDisplayContent secondaryDisplay =
-                new TestDisplayContent.Builder(mService, 1000, 1500).build();
+                new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
         mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay,
                 false /* includingParents */);
         final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
@@ -793,7 +793,7 @@
         final Task topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
-        new ActivityBuilder(mService).setTask(topTask).build();
+        new ActivityBuilder(mAtm).setTask(topTask).build();
 
         // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
         final ActivityOptions options = ActivityOptions.makeBasic()
@@ -815,16 +815,16 @@
         final ActivityStarter starter = prepareStarter(
                 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
         final ActivityRecord reusableActivity =
-                new ActivityBuilder(mService).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord topActivity =
-                new ActivityBuilder(mService).setCreateTask(true).build();
+                new ActivityBuilder(mAtm).setCreateTask(true).build();
 
         // Make sure topActivity is on top
         topActivity.getRootTask().moveToFront("testWasVisibleInRestartAttempt");
         reusableActivity.setVisible(false);
 
         final TaskChangeNotificationController taskChangeNotifier =
-                mService.getTaskChangeNotificationController();
+                mAtm.getTaskChangeNotificationController();
         spyOn(taskChangeNotifier);
 
         Task task = topActivity.getTask();
@@ -853,7 +853,7 @@
                 .setComponent(componentName)
                 .setStack(stack)
                 .build();
-        return new ActivityBuilder(mService)
+        return new ActivityBuilder(mAtm)
                 .setComponent(componentName)
                 .setLaunchMode(LAUNCH_SINGLE_TASK)
                 .setTask(task)
@@ -876,7 +876,7 @@
                 true /* onTop */);
 
         // Put an activity on default display as the top focused activity.
-        final ActivityRecord topActivity = new ActivityBuilder(mService)
+        final ActivityRecord topActivity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setLaunchMode(LAUNCH_SINGLE_TASK)
                 .build();
@@ -900,7 +900,7 @@
     @Test
     public void testFreezeTaskListActivityOption() {
         RecentTasks recentTasks = mock(RecentTasks.class);
-        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        mAtm.mStackSupervisor.setRecentTasks(recentTasks);
         doReturn(true).when(recentTasks).isCallerRecents(anyInt());
 
         final ActivityStarter starter = prepareStarter(0 /* flags */);
@@ -922,7 +922,7 @@
     @Test
     public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
         RecentTasks recentTasks = mock(RecentTasks.class);
-        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        mAtm.mStackSupervisor.setRecentTasks(recentTasks);
         doReturn(true).when(recentTasks).isCallerRecents(anyInt());
 
         final ActivityStarter starter = prepareStarter(0 /* flags */);
@@ -959,7 +959,7 @@
         intent.setComponent(ActivityBuilder.getDefaultComponent());
 
         doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any());
-        starter.setIntent(intent).mRequest.resolveActivity(mService.mStackSupervisor);
+        starter.setIntent(intent).mRequest.resolveActivity(mAtm.mStackSupervisor);
 
         // Make sure the client intent won't be modified.
         assertThat(intent.getComponent()).isNotNull();
@@ -985,9 +985,9 @@
     @Test
     public void testRecycleTaskFromAnotherUser() {
         final ActivityStarter starter = prepareStarter(0 /* flags */);
-        starter.mStartActivity = new ActivityBuilder(mService).build();
-        final Task task = new TaskBuilder(mService.mStackSupervisor)
-                .setStack(mService.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
+        starter.mStartActivity = new ActivityBuilder(mAtm).build();
+        final Task task = new TaskBuilder(mAtm.mStackSupervisor)
+                .setStack(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
                         WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
                 .setUserId(10)
                 .build();
@@ -1001,7 +1001,7 @@
     public void testTargetStackInSplitScreen() {
         final ActivityStarter starter =
                 prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetLaunchStack */);
-        final ActivityRecord top = new ActivityBuilder(mService).setCreateTask(true).build();
+        final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityOptions options = ActivityOptions.makeBasic();
         final ActivityRecord[] outActivity = new ActivityRecord[1];
 
@@ -1012,7 +1012,7 @@
         assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
 
         // Move activity to split-screen-primary stack and make sure it has the focus.
-        TestSplitOrganizer splitOrg = new TestSplitOrganizer(mService, top.getDisplayId());
+        TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayId());
         top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
         top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
 
@@ -1026,7 +1026,7 @@
     @Test
     public void testActivityStart_expectAddedToRecentTask() {
         RecentTasks recentTasks = mock(RecentTasks.class);
-        mService.mStackSupervisor.setRecentTasks(recentTasks);
+        mAtm.mStackSupervisor.setRecentTasks(recentTasks);
         doReturn(true).when(recentTasks).isCallerRecents(anyInt());
 
         final ActivityStarter starter = prepareStarter(0 /* flags */);
@@ -1044,10 +1044,10 @@
 
         starter.setReason("testAllSplitScreenPrimaryActivitiesAreResumed");
 
-        final ActivityRecord targetRecord = new ActivityBuilder(mService).build();
+        final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
         targetRecord.setFocusable(false);
         targetRecord.setVisibility(false);
-        final ActivityRecord sourceRecord = new ActivityBuilder(mService).build();
+        final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).build();
 
         final Task stack = spy(
                 mRootWindowContainer.getDefaultTaskDisplayArea()
@@ -1059,7 +1059,7 @@
         doReturn(stack).when(mRootWindowContainer)
                 .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
 
-        starter.mStartActivity = new ActivityBuilder(mService).build();
+        starter.mStartActivity = new ActivityBuilder(mAtm).build();
 
         // When
         starter.startActivityInner(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index f8faae6..2e988af 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -60,14 +60,14 @@
 @Presubmit
 @MediumTest
 @RunWith(WindowTestRunner.class)
-public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
+public class ActivityTaskManagerServiceTests extends WindowTestsBase {
 
     private final ArgumentCaptor<ClientTransaction> mClientTransactionCaptor =
             ArgumentCaptor.forClass(ClientTransaction.class);
 
     @Before
     public void setUp() throws Exception {
-        setBooted(mService);
+        setBooted(mAtm);
     }
 
     /** Verify that activity is finished correctly upon request. */
@@ -75,13 +75,13 @@
     public void testActivityFinish() {
         final Task stack = new StackBuilder(mRootWindowContainer).build();
         final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
-        assertTrue("Activity must be finished", mService.finishActivity(activity.appToken,
+        assertTrue("Activity must be finished", mAtm.finishActivity(activity.appToken,
                 0 /* resultCode */, null /* resultData */,
                 Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
         assertTrue(activity.finishing);
 
         assertTrue("Duplicate activity finish request must also return 'true'",
-                mService.finishActivity(activity.appToken, 0 /* resultCode */,
+                mAtm.finishActivity(activity.appToken, 0 /* resultCode */,
                         null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
     }
 
@@ -90,10 +90,10 @@
         final Task stack = new StackBuilder(mRootWindowContainer).build();
         final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
         final ClientLifecycleManager mockLifecycleManager = mock(ClientLifecycleManager.class);
-        doReturn(mockLifecycleManager).when(mService).getLifecycleManager();
+        doReturn(mockLifecycleManager).when(mAtm).getLifecycleManager();
         doReturn(true).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
 
-        mService.requestPictureInPictureMode(activity.token);
+        mAtm.requestPictureInPictureMode(activity.token);
 
         verify(mockLifecycleManager).scheduleTransaction(mClientTransactionCaptor.capture());
         final ClientTransaction transaction = mClientTransactionCaptor.getValue();
@@ -108,11 +108,11 @@
     public void testOnPictureInPictureRequested_cannotEnterPip() throws RemoteException {
         final Task stack = new StackBuilder(mRootWindowContainer).build();
         final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
-        ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+        ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
         doReturn(false).when(activity).inPinnedWindowingMode();
         doReturn(false).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
 
-        mService.requestPictureInPictureMode(activity.token);
+        mAtm.requestPictureInPictureMode(activity.token);
 
         // Check enter no transactions with enter pip requests are made.
         verify(lifecycleManager, times(0)).scheduleTransaction(any());
@@ -122,10 +122,10 @@
     public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException {
         final Task stack = new StackBuilder(mRootWindowContainer).build();
         final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
-        ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+        ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
         doReturn(true).when(activity).inPinnedWindowingMode();
 
-        mService.requestPictureInPictureMode(activity.token);
+        mAtm.requestPictureInPictureMode(activity.token);
 
         // Check that no transactions with enter pip requests are made.
         verify(lifecycleManager, times(0)).scheduleTransaction(any());
@@ -158,14 +158,14 @@
             @Override
             public void onFixedRotationFinished(int displayId) {}
         };
-        mService.mWindowManager.registerDisplayWindowListener(listener);
+        mAtm.mWindowManager.registerDisplayWindowListener(listener);
         // Check that existing displays call added
         assertEquals(1, added.size());
         assertEquals(0, changed.size());
         assertEquals(0, removed.size());
         added.clear();
         // Check adding a display
-        DisplayContent newDisp1 = new TestDisplayContent.Builder(mService, 600, 800).build();
+        DisplayContent newDisp1 = new TestDisplayContent.Builder(mAtm, 600, 800).build();
         assertEquals(1, added.size());
         assertEquals(0, changed.size());
         assertEquals(0, removed.size());
@@ -174,7 +174,7 @@
         Configuration c = new Configuration(newDisp1.getRequestedOverrideConfiguration());
         c.windowConfiguration.setBounds(new Rect(0, 0, 1000, 1300));
         newDisp1.onRequestedOverrideConfigurationChanged(c);
-        mService.mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
+        mAtm.mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
                 newDisp1.mDisplayId, false /* markFrozenIfConfigChanged */,
                 false /* deferResume */);
         assertEquals(0, added.size());
@@ -214,13 +214,13 @@
         //mock other operations
         doReturn(true).when(record)
                 .checkEnterPictureInPictureState("enterPictureInPictureMode", false);
-        doReturn(false).when(mService).isInPictureInPictureMode(any());
-        doReturn(false).when(mService).isKeyguardLocked();
+        doReturn(false).when(mAtm).isInPictureInPictureMode(any());
+        doReturn(false).when(mAtm).isKeyguardLocked();
 
         //to simulate NPE
         doReturn(null).when(record).getParent();
 
-        mService.enterPictureInPictureMode(token, params);
+        mAtm.enterPictureInPictureMode(token, params);
         //if record's null parent is not handled gracefully, test will fail with NPE
 
         mockSession.finishMocking();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
deleted file mode 100644
index 5be2f04..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-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_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-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.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.IApplicationThread;
-import android.app.WindowConfiguration;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.service.voice.IVoiceInteractionSession;
-import android.view.SurfaceControl;
-import android.window.ITaskOrganizer;
-import android.window.WindowContainerToken;
-
-import com.android.server.AttributeCache;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-
-/**
- * A base class to handle common operations in activity related unit tests.
- */
-class ActivityTestsBase extends SystemServiceTestsBase {
-    final Context mContext = getInstrumentation().getTargetContext();
-
-    ActivityTaskManagerService mService;
-    RootWindowContainer mRootWindowContainer;
-    ActivityStackSupervisor mSupervisor;
-
-    // Default package name
-    static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
-
-    // Default base activity name
-    private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
-
-    @BeforeClass
-    public static void setUpOnceBase() {
-        AttributeCache.init(getInstrumentation().getTargetContext());
-    }
-
-    @Before
-    public void setUpBase() {
-        mService = mSystemServicesTestRule.getActivityTaskManagerService();
-        mSupervisor = mService.mStackSupervisor;
-        mRootWindowContainer = mService.mRootWindowContainer;
-    }
-
-    /** Creates and adds a {@link TestDisplayContent} to supervisor at the given position. */
-    TestDisplayContent addNewDisplayContentAt(int position) {
-        return new TestDisplayContent.Builder(mService, 1000, 1500).setPosition(position).build();
-    }
-
-    /** Sets the default minimum task size to 1 so that tests can use small task sizes */
-    public void removeGlobalMinSizeRestriction() {
-        mService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
-    }
-
-    /**
-     * Builder for creating new activities.
-     */
-    protected static class ActivityBuilder {
-        // An id appended to the end of the component name to make it unique
-        private static int sCurrentActivityId = 0;
-
-        private final ActivityTaskManagerService mService;
-
-        private ComponentName mComponent;
-        private String mTargetActivity;
-        private Task mTask;
-        private String mProcessName = "name";
-        private String mAffinity;
-        private int mUid = 12345;
-        private boolean mCreateTask;
-        private Task mStack;
-        private int mActivityFlags;
-        private int mLaunchMode;
-        private int mResizeMode = RESIZE_MODE_RESIZEABLE;
-        private float mMaxAspectRatio;
-        private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
-        private boolean mLaunchTaskBehind;
-        private int mConfigChanges;
-        private int mLaunchedFromPid;
-        private int mLaunchedFromUid;
-        private WindowProcessController mWpc;
-        private Bundle mIntentExtras;
-
-        ActivityBuilder(ActivityTaskManagerService service) {
-            mService = service;
-        }
-
-        ActivityBuilder setComponent(ComponentName component) {
-            mComponent = component;
-            return this;
-        }
-
-        ActivityBuilder setTargetActivity(String targetActivity) {
-            mTargetActivity = targetActivity;
-            return this;
-        }
-
-        ActivityBuilder setIntentExtras(Bundle extras) {
-            mIntentExtras = extras;
-            return this;
-        }
-
-        static ComponentName getDefaultComponent() {
-            return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
-                    DEFAULT_COMPONENT_PACKAGE_NAME);
-        }
-
-        ActivityBuilder setTask(Task task) {
-            mTask = task;
-            return this;
-        }
-
-        ActivityBuilder setActivityFlags(int flags) {
-            mActivityFlags = flags;
-            return this;
-        }
-
-        ActivityBuilder setLaunchMode(int launchMode) {
-            mLaunchMode = launchMode;
-            return this;
-        }
-
-        ActivityBuilder setStack(Task stack) {
-            mStack = stack;
-            return this;
-        }
-
-        ActivityBuilder setCreateTask(boolean createTask) {
-            mCreateTask = createTask;
-            return this;
-        }
-
-        ActivityBuilder setProcessName(String name) {
-            mProcessName = name;
-            return this;
-        }
-
-        ActivityBuilder setUid(int uid) {
-            mUid = uid;
-            return this;
-        }
-
-        ActivityBuilder setResizeMode(int resizeMode) {
-            mResizeMode = resizeMode;
-            return this;
-        }
-
-        ActivityBuilder setMaxAspectRatio(float maxAspectRatio) {
-            mMaxAspectRatio = maxAspectRatio;
-            return this;
-        }
-
-        ActivityBuilder setScreenOrientation(int screenOrientation) {
-            mScreenOrientation = screenOrientation;
-            return this;
-        }
-
-        ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) {
-            mLaunchTaskBehind = launchTaskBehind;
-            return this;
-        }
-
-        ActivityBuilder setConfigChanges(int configChanges) {
-            mConfigChanges = configChanges;
-            return this;
-        }
-
-        ActivityBuilder setLaunchedFromPid(int pid) {
-            mLaunchedFromPid = pid;
-            return this;
-        }
-
-        ActivityBuilder setLaunchedFromUid(int uid) {
-            mLaunchedFromUid = uid;
-            return this;
-        }
-
-        ActivityBuilder setUseProcess(WindowProcessController wpc) {
-            mWpc = wpc;
-            return this;
-        }
-
-        ActivityBuilder setAffinity(String affinity) {
-            mAffinity = affinity;
-            return this;
-        }
-
-        ActivityRecord build() {
-            SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
-            try {
-                mService.deferWindowLayout();
-                return buildInner();
-            } finally {
-                mService.continueWindowLayout();
-            }
-        }
-
-        ActivityRecord buildInner() {
-            if (mComponent == null) {
-                final int id = sCurrentActivityId++;
-                mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
-                        DEFAULT_COMPONENT_CLASS_NAME + id);
-            }
-
-            if (mCreateTask) {
-                mTask = new TaskBuilder(mService.mStackSupervisor)
-                        .setComponent(mComponent)
-                        .setStack(mStack).build();
-            } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
-                    mStack.getWindowingMode(), mStack.getActivityType())) {
-                // The stack can be the task root.
-                mTask = mStack;
-            }
-
-            Intent intent = new Intent();
-            intent.setComponent(mComponent);
-            if (mIntentExtras != null) {
-                intent.putExtras(mIntentExtras);
-            }
-            final ActivityInfo aInfo = new ActivityInfo();
-            aInfo.applicationInfo = new ApplicationInfo();
-            aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
-            aInfo.applicationInfo.packageName = mComponent.getPackageName();
-            aInfo.applicationInfo.uid = mUid;
-            aInfo.processName = mProcessName;
-            aInfo.packageName = mComponent.getPackageName();
-            aInfo.name = mComponent.getClassName();
-            if (mTargetActivity != null) {
-                aInfo.targetActivity = mTargetActivity;
-            }
-            aInfo.flags |= mActivityFlags;
-            aInfo.launchMode = mLaunchMode;
-            aInfo.resizeMode = mResizeMode;
-            aInfo.maxAspectRatio = mMaxAspectRatio;
-            aInfo.screenOrientation = mScreenOrientation;
-            aInfo.configChanges |= mConfigChanges;
-            aInfo.taskAffinity = mAffinity;
-
-            ActivityOptions options = null;
-            if (mLaunchTaskBehind) {
-                options = ActivityOptions.makeTaskLaunchBehind();
-            }
-
-            final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
-                    mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
-                    null, null, intent, null, aInfo /*aInfo*/, new Configuration(),
-                    null /* resultTo */, null /* resultWho */, 0 /* reqCode */,
-                    false /*componentSpecified*/, false /* rootVoiceInteraction */,
-                    mService.mStackSupervisor, options, null /* sourceRecord */);
-            spyOn(activity);
-            if (mTask != null) {
-                // fullscreen value is normally read from resources in ctor, so for testing we need
-                // to set it somewhere else since we can't mock resources.
-                doReturn(true).when(activity).occludesParent();
-                doReturn(true).when(activity).fillsParent();
-                mTask.addChild(activity);
-                // Make visible by default...
-                activity.setVisible(true);
-            }
-
-            final WindowProcessController wpc;
-            if (mWpc != null) {
-                wpc = mWpc;
-            } else {
-                wpc = new WindowProcessController(mService,
-                        aInfo.applicationInfo, mProcessName, mUid,
-                        UserHandle.getUserId(12345), mock(Object.class),
-                        mock(WindowProcessListener.class));
-                wpc.setThread(mock(IApplicationThread.class));
-            }
-            wpc.setThread(mock(IApplicationThread.class));
-            activity.setProcess(wpc);
-            doReturn(wpc).when(mService).getProcessController(
-                    activity.processName, activity.info.applicationInfo.uid);
-
-            // Resume top activities to make sure all other signals in the system are connected.
-            mService.mRootWindowContainer.resumeFocusedStacksTopActivities();
-            return activity;
-        }
-    }
-
-    /**
-     * Builder for creating new tasks.
-     */
-    protected static class TaskBuilder {
-        private final ActivityStackSupervisor mSupervisor;
-
-        private ComponentName mComponent;
-        private String mPackage;
-        private int mFlags = 0;
-        // Task id 0 is reserved in ARC for the home app.
-        private int mTaskId = SystemServicesTestRule.sNextTaskId++;
-        private int mUserId = 0;
-        private IVoiceInteractionSession mVoiceSession;
-        private boolean mCreateStack = true;
-
-        private Task mStack;
-        private TaskDisplayArea mTaskDisplayArea;
-
-        TaskBuilder(ActivityStackSupervisor supervisor) {
-            mSupervisor = supervisor;
-        }
-
-        TaskBuilder setComponent(ComponentName component) {
-            mComponent = component;
-            return this;
-        }
-
-        TaskBuilder setPackage(String packageName) {
-            mPackage = packageName;
-            return this;
-        }
-
-        /**
-         * Set to {@code true} by default, set to {@code false} to prevent the task from
-         * automatically creating a parent stack.
-         */
-        TaskBuilder setCreateStack(boolean createStack) {
-            mCreateStack = createStack;
-            return this;
-        }
-
-        TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
-            mVoiceSession = session;
-            return this;
-        }
-
-        TaskBuilder setFlags(int flags) {
-            mFlags = flags;
-            return this;
-        }
-
-        TaskBuilder setTaskId(int taskId) {
-            mTaskId = taskId;
-            return this;
-        }
-
-        TaskBuilder setUserId(int userId) {
-            mUserId = userId;
-            return this;
-        }
-
-        TaskBuilder setStack(Task stack) {
-            mStack = stack;
-            return this;
-        }
-
-        TaskBuilder setDisplay(DisplayContent display) {
-            mTaskDisplayArea = display.getDefaultTaskDisplayArea();
-            return this;
-        }
-
-        Task build() {
-            SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
-
-            if (mStack == null && mCreateStack) {
-                TaskDisplayArea displayArea = mTaskDisplayArea != null ? mTaskDisplayArea
-                        : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
-                mStack = displayArea.createStack(
-                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-                spyOn(mStack);
-            }
-
-            final ActivityInfo aInfo = new ActivityInfo();
-            aInfo.applicationInfo = new ApplicationInfo();
-            aInfo.applicationInfo.packageName = mPackage;
-
-            Intent intent = new Intent();
-            if (mComponent == null) {
-                mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
-                        DEFAULT_COMPONENT_CLASS_NAME);
-            }
-
-            intent.setComponent(mComponent);
-            intent.setFlags(mFlags);
-
-            final Task task = new Task(mSupervisor.mService, mTaskId, aInfo,
-                    intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
-                    null /*taskDescription*/, mStack);
-            spyOn(task);
-            task.mUserId = mUserId;
-
-            if (mStack != null) {
-                mStack.moveToFront("test");
-                mStack.addChild(task, true, true);
-            }
-
-            return task;
-        }
-    }
-
-    static class StackBuilder {
-        private final RootWindowContainer mRootWindowContainer;
-        private DisplayContent mDisplay;
-        private TaskDisplayArea mTaskDisplayArea;
-        private int mStackId = -1;
-        private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
-        private int mActivityType = ACTIVITY_TYPE_STANDARD;
-        private boolean mOnTop = true;
-        private boolean mCreateActivity = true;
-        private ActivityInfo mInfo;
-        private Intent mIntent;
-
-        StackBuilder(RootWindowContainer root) {
-            mRootWindowContainer = root;
-            mDisplay = mRootWindowContainer.getDefaultDisplay();
-            mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
-        }
-
-        StackBuilder setWindowingMode(int windowingMode) {
-            mWindowingMode = windowingMode;
-            return this;
-        }
-
-        StackBuilder setActivityType(int activityType) {
-            mActivityType = activityType;
-            return this;
-        }
-
-        StackBuilder setStackId(int stackId) {
-            mStackId = stackId;
-            return this;
-        }
-
-        /**
-         * Set the parent {@link DisplayContent} and use the default task display area. Overrides
-         * the task display area, if was set before.
-         */
-        StackBuilder setDisplay(DisplayContent display) {
-            mDisplay = display;
-            mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
-            return this;
-        }
-
-        /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */
-        StackBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
-            mTaskDisplayArea = taskDisplayArea;
-            mDisplay = mTaskDisplayArea.mDisplayContent;
-            return this;
-        }
-
-        StackBuilder setOnTop(boolean onTop) {
-            mOnTop = onTop;
-            return this;
-        }
-
-        StackBuilder setCreateActivity(boolean createActivity) {
-            mCreateActivity = createActivity;
-            return this;
-        }
-
-        StackBuilder setActivityInfo(ActivityInfo info) {
-            mInfo = info;
-            return this;
-        }
-
-        StackBuilder setIntent(Intent intent) {
-            mIntent = intent;
-            return this;
-        }
-
-        Task build() {
-            SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock);
-
-            final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId();
-            final Task stack = mTaskDisplayArea.createStackUnchecked(
-                    mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
-                    false /* createdByOrganizer */);
-            final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
-
-            if (mCreateActivity) {
-                new ActivityBuilder(supervisor.mService)
-                        .setCreateTask(true)
-                        .setStack(stack)
-                        .build();
-                if (mOnTop) {
-                    // We move the task to front again in order to regain focus after activity
-                    // added to the stack. Or {@link DisplayContent#mPreferredTopFocusableStack}
-                    // could be other stacks (e.g. home stack).
-                    stack.moveToFront("createActivityStack");
-                } else {
-                    stack.moveToBack("createActivityStack", null);
-                }
-            }
-            spyOn(stack);
-
-            doNothing().when(stack).startActivityLocked(
-                    any(), any(), anyBoolean(), anyBoolean(), any());
-
-            return stack;
-        }
-
-    }
-
-    static class TestSplitOrganizer extends ITaskOrganizer.Stub {
-        final ActivityTaskManagerService mService;
-        Task mPrimary;
-        Task mSecondary;
-        boolean mInSplit = false;
-        // moves everything to secondary. Most tests expect this since sysui usually does it.
-        boolean mMoveToSecondaryOnEnter = true;
-        int mDisplayId;
-        TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
-            mService = service;
-            mDisplayId = displayId;
-            mService.mTaskOrganizerController.registerTaskOrganizer(this,
-                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-            mService.mTaskOrganizerController.registerTaskOrganizer(this,
-                    WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-            WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
-                    displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
-            mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
-            WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
-                    displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
-            mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
-        }
-        TestSplitOrganizer(ActivityTaskManagerService service) {
-            this(service,
-                    service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId);
-        }
-        public void setMoveToSecondaryOnEnter(boolean move) {
-            mMoveToSecondaryOnEnter = move;
-        }
-        @Override
-        public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
-        }
-        @Override
-        public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
-        }
-        @Override
-        public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
-            if (mInSplit) {
-                return;
-            }
-            if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) {
-                // Not populated
-                return;
-            }
-            if (info.configuration.windowConfiguration.getWindowingMode()
-                    != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                return;
-            }
-            mInSplit = true;
-            if (!mMoveToSecondaryOnEnter) {
-                return;
-            }
-            mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
-                    mSecondary.mRemoteToken.toWindowContainerToken());
-            DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
-            dc.forAllTaskDisplayAreas(taskDisplayArea -> {
-                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
-                    final Task stack = taskDisplayArea.getStackAt(sNdx);
-                    if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
-                        stack.reparent(mSecondary, POSITION_BOTTOM);
-                    }
-                }
-            });
-        }
-        @Override
-        public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
-        }
-    };
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 97a2ebe..888935e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -431,7 +431,7 @@
         doCallRealMethod().when(mStack).startActivityLocked(
                 any(), any(), anyBoolean(), anyBoolean(), any());
         // Make mVisibleSetFromTransferredStartingWindow true.
-        final ActivityRecord middle = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+        final ActivityRecord middle = new ActivityBuilder(mWm.mAtmService)
                 .setTask(mTask).build();
         mStack.startActivityLocked(middle, null /* focusedTopActivity */,
                 false /* newTask */, false /* keepCurTransition */, null /* options */);
@@ -440,7 +440,7 @@
         assertNull(mActivity.startingWindow);
         assertHasStartingWindow(middle);
 
-        final ActivityRecord top = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+        final ActivityRecord top = new ActivityBuilder(mWm.mAtmService)
                 .setTask(mTask).build();
         // Expect the visibility should be updated to true when transferring starting window from
         // a visible activity.
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 edf1536..0cc6159 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -850,13 +850,13 @@
                 IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
 
         final Task stack =
-                new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
+                new StackBuilder(mWm.mAtmService.mRootWindowContainer)
                         .setDisplay(dc)
                         .build();
         doReturn(true).when(stack).isVisible();
 
         final Task freeformStack =
-                new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
+                new StackBuilder(mWm.mAtmService.mRootWindowContainer)
                         .setDisplay(dc)
                         .setWindowingMode(WINDOWING_MODE_FREEFORM)
                         .build();
@@ -881,9 +881,8 @@
                 IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
         final int newOrientation = getRotatedOrientation(dc);
 
-        final Task stack =
-                new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
-                        .setDisplay(dc).build();
+        final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
+                .setDisplay(dc).build();
         final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
 
         activity.setRequestedOrientation(newOrientation);
@@ -901,9 +900,8 @@
                 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
         final int newOrientation = getRotatedOrientation(dc);
 
-        final Task stack =
-                new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
-                        .setDisplay(dc).build();
+        final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
+                .setDisplay(dc).build();
         final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
 
         activity.setRequestedOrientation(newOrientation);
@@ -1213,7 +1211,7 @@
         verify(t, never()).setPosition(any(), eq(0), eq(0));
 
         // Launch another activity before the transition is finished.
-        final ActivityRecord app2 = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final ActivityRecord app2 = new StackBuilder(mWm.mRoot)
                 .setDisplay(mDisplayContent).build().getTopMostActivity();
         app2.setVisible(false);
         mDisplayContent.mOpeningApps.add(app2);
@@ -1247,8 +1245,7 @@
         final ActivityRecord app = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD);
         final Task task = app.getTask();
-        final ActivityRecord app2 = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
-                .setTask(task).build();
+        final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
         mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
         doReturn(true).when(task).isAppTransitioning();
         // If the task is animating transition, this should be no-op.
@@ -1513,8 +1510,7 @@
     @Test
     public void testSetWindowingModeAtomicallyUpdatesWindoingModeAndDisplayWindowingMode() {
         final DisplayContent dc = createNewDisplay();
-        final Task stack =
-                new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootWindowContainer)
+        final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
                 .setDisplay(dc)
                 .build();
         doAnswer(invocation -> {
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 a7a8505..820eca4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -68,14 +68,14 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class LaunchParamsControllerTests extends ActivityTestsBase {
+public class LaunchParamsControllerTests extends WindowTestsBase {
     private LaunchParamsController mController;
     private TestLaunchParamsPersister mPersister;
 
     @Before
     public void setUp() throws Exception {
         mPersister = new TestLaunchParamsPersister();
-        mController = new LaunchParamsController(mService, mPersister);
+        mController = new LaunchParamsController(mAtm, mPersister);
     }
 
     /**
@@ -87,8 +87,8 @@
                 positioner = mock(LaunchParamsModifier.class);
         mController.registerModifier(positioner);
 
-        final ActivityRecord record = new ActivityBuilder(mService).build();
-        final ActivityRecord source = new ActivityBuilder(mService).build();
+        final ActivityRecord record = new ActivityBuilder(mAtm).build();
+        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);
 
@@ -108,7 +108,7 @@
 
         final ComponentName name = new ComponentName("com.android.foo", ".BarActivity");
         final int userId = 0;
-        final ActivityRecord activity = new ActivityBuilder(mService).setComponent(name)
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setComponent(name)
                 .setUid(userId).build();
         final LaunchParams expected = new LaunchParams();
         expected.mPreferredTaskDisplayArea = mock(TaskDisplayArea.class);
@@ -228,10 +228,10 @@
     @Test
     public void testVrPreferredDisplay() {
         final TestDisplayContent vrDisplay = createNewDisplayContent();
-        mService.mVr2dDisplayId = vrDisplay.mDisplayId;
+        mAtm.mVr2dDisplayId = vrDisplay.mDisplayId;
 
         final LaunchParams result = new LaunchParams();
-        final ActivityRecord vrActivity = new ActivityBuilder(mService).build();
+        final ActivityRecord vrActivity = new ActivityBuilder(mAtm).build();
         vrActivity.requestedVrComponent = vrActivity.mActivityComponent;
 
         // VR activities should always land on default display.
@@ -241,7 +241,7 @@
                 result.mPreferredTaskDisplayArea);
 
         // Otherwise, always lands on VR 2D display.
-        final ActivityRecord vr2dActivity = new ActivityBuilder(mService).build();
+        final ActivityRecord vr2dActivity = new ActivityBuilder(mAtm).build();
         mController.calculate(null /*task*/, null /*layout*/, vr2dActivity /*activity*/,
                 null /*source*/, null /*options*/, PHASE_BOUNDS, result);
         assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea);
@@ -249,7 +249,7 @@
                 null /*options*/, PHASE_BOUNDS, result);
         assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea);
 
-        mService.mVr2dDisplayId = INVALID_DISPLAY;
+        mAtm.mVr2dDisplayId = INVALID_DISPLAY;
     }
 
 
@@ -262,8 +262,8 @@
         final LaunchParamsModifier positioner = mock(LaunchParamsModifier.class);
         mController.registerModifier(positioner);
 
-        final ActivityRecord record = new ActivityBuilder(mService).build();
-        final ActivityRecord source = new ActivityBuilder(mService).build();
+        final ActivityRecord record = new ActivityBuilder(mAtm).build();
+        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);
 
@@ -284,7 +284,7 @@
         final TaskDisplayArea preferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
         params.mPreferredTaskDisplayArea = preferredTaskDisplayArea;
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
@@ -305,7 +305,7 @@
         final int windowingMode = WINDOWING_MODE_FREEFORM;
         params.mWindowingMode = windowingMode;
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
@@ -330,7 +330,7 @@
         params.mWindowingMode = WINDOWING_MODE_FREEFORM;
         params.mBounds.set(expected);
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
@@ -355,7 +355,7 @@
         params.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
         params.mBounds.set(expected);
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mAtm.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index e389a53..18a2d13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -65,7 +65,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class LaunchParamsPersisterTests extends ActivityTestsBase {
+public class LaunchParamsPersisterTests extends WindowTestsBase {
     private static final int TEST_USER_ID = 3;
     private static final int ALTERNATIVE_USER_ID = 0;
     private static final ComponentName TEST_COMPONENT =
@@ -109,7 +109,7 @@
         deleteRecursively(mFolder);
 
         mDisplayUniqueId = "test:" + sNextUniqueId++;
-        mTestDisplay = new TestDisplayContent.Builder(mService, 1000, 1500)
+        mTestDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1500)
                 .setUniqueId(mDisplayUniqueId).build();
         when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId)))
                 .thenReturn(mTestDisplay);
@@ -172,7 +172,7 @@
     public void testFetchesSameResultWithActivity() {
         mTarget.saveTask(mTestTask);
 
-        final ActivityRecord activity = new ActivityBuilder(mService).setComponent(TEST_COMPONENT)
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setComponent(TEST_COMPONENT)
                 .setUid(TEST_USER_ID * UserHandle.PER_USER_RANGE).build();
 
         mTarget.getLaunchParams(null, activity, mResult);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index a137cde..044f819 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -168,8 +168,8 @@
 
     @Test
     public void testStartLockTaskMode_once() throws Exception {
-        // GIVEN a task record with whitelisted auth
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN a task record with allowlisted auth
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
 
         // WHEN calling setLockTaskMode for LOCKED mode without resuming
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -185,9 +185,9 @@
 
     @Test
     public void testStartLockTaskMode_twice() throws Exception {
-        // GIVEN two task records with whitelisted auth
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
-        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN two task records with allowlisted auth
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
 
         // WHEN calling setLockTaskMode for LOCKED mode on both tasks
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -205,7 +205,7 @@
 
     @Test
     public void testStartLockTaskMode_pinningRequest() {
-        // GIVEN a task record that is not whitelisted, i.e. with pinned auth
+        // GIVEN a task record that is not allowlisted, i.e. with pinned auth
         Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
 
         // WHEN calling startLockTaskMode
@@ -236,23 +236,23 @@
 
     @Test
     public void testLockTaskViolation() {
-        // GIVEN one task record with whitelisted auth that is in lock task mode
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN one task record with allowlisted auth that is in lock task mode
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN it's not a lock task violation to try and launch this task without clearing
         assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
 
-        // THEN it's a lock task violation to launch another task that is not whitelisted
+        // THEN it's a lock task violation to launch another task that is not allowlisted
         assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
                 Task.LOCK_TASK_AUTH_PINNABLE)));
         // THEN it's a lock task violation to launch another task that is disallowed from lock task
         assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
                 Task.LOCK_TASK_AUTH_DONT_LOCK)));
 
-        // THEN it's no a lock task violation to launch another task that is whitelisted
+        // THEN it's no a lock task violation to launch another task that is allowlisted
         assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
-                Task.LOCK_TASK_AUTH_WHITELISTED)));
+                Task.LOCK_TASK_AUTH_ALLOWLISTED)));
         assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
                 Task.LOCK_TASK_AUTH_LAUNCHABLE)));
         // THEN it's not a lock task violation to launch another task that is priv launchable
@@ -262,8 +262,8 @@
 
     @Test
     public void testLockTaskViolation_emergencyCall() {
-        // GIVEN one task record with whitelisted auth that is in lock task mode
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN one task record with allowlisted auth that is in lock task mode
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // GIVEN tasks necessary for emergency calling
@@ -294,8 +294,8 @@
 
     @Test
     public void testStopLockTaskMode() throws Exception {
-        // GIVEN one task record with whitelisted auth that is in lock task mode
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN one task record with allowlisted auth that is in lock task mode
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // WHEN the same caller calls stopLockTaskMode
@@ -311,8 +311,8 @@
 
     @Test(expected = SecurityException.class)
     public void testStopLockTaskMode_differentCaller() {
-        // GIVEN one task record with whitelisted auth that is in lock task mode
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN one task record with allowlisted auth that is in lock task mode
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // WHEN a different caller calls stopLockTaskMode
@@ -323,8 +323,8 @@
 
     @Test
     public void testStopLockTaskMode_systemCaller() {
-        // GIVEN one task record with whitelisted auth that is in lock task mode
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN one task record with allowlisted auth that is in lock task mode
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // WHEN system calls stopLockTaskMode
@@ -336,9 +336,9 @@
 
     @Test
     public void testStopLockTaskMode_twoTasks() throws Exception {
-        // GIVEN two task records with whitelisted auth that is in lock task mode
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
-        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN two task records with allowlisted auth that is in lock task mode
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
         mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
 
@@ -357,9 +357,9 @@
 
     @Test
     public void testStopLockTaskMode_rootTask() throws Exception {
-        // GIVEN two task records with whitelisted auth that is in lock task mode
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
-        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN two task records with allowlisted auth that is in lock task mode
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
         mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
 
@@ -405,9 +405,9 @@
 
     @Test
     public void testClearLockedTasks() throws Exception {
-        // GIVEN two task records with whitelisted auth that is in lock task mode
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
-        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        // GIVEN two task records with allowlisted auth that is in lock task mode
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
         mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
 
@@ -434,7 +434,7 @@
                 .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
 
         // AND there is a task record
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -454,7 +454,7 @@
                 .thenReturn(true);
 
         // AND there is a task record
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -471,7 +471,7 @@
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
 
         // AND there is a task record
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -488,7 +488,7 @@
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
 
         // AND there is a task record
-        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -500,45 +500,45 @@
 
     @Test
     public void testUpdateLockTaskPackages() {
-        String[] whitelist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
-        String[] whitelist2 = {TEST_PACKAGE_NAME};
+        String[] allowlist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+        String[] allowlist2 = {TEST_PACKAGE_NAME};
 
-        // No package is whitelisted initially
-        for (String pkg : whitelist1) {
-            assertFalse("Package shouldn't be whitelisted: " + pkg,
-                    mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
-            assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
-                    mLockTaskController.isPackageWhitelisted(0, pkg));
+        // No package is allowlisted initially
+        for (String pkg : allowlist1) {
+            assertFalse("Package shouldn't be allowlisted: " + pkg,
+                    mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+            assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+                    mLockTaskController.isPackageAllowlisted(0, pkg));
         }
 
-        // Apply whitelist
-        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist1);
+        // Apply allowlist
+        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist1);
 
-        // Assert the whitelist is applied to the correct user
-        for (String pkg : whitelist1) {
-            assertTrue("Package should be whitelisted: " + pkg,
-                    mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
-            assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
-                    mLockTaskController.isPackageWhitelisted(0, pkg));
+        // Assert the allowlist is applied to the correct user
+        for (String pkg : allowlist1) {
+            assertTrue("Package should be allowlisted: " + pkg,
+                    mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+            assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+                    mLockTaskController.isPackageAllowlisted(0, pkg));
         }
 
-        // Update whitelist
-        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist2);
+        // Update allowlist
+        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist2);
 
-        // Assert the new whitelist is applied
-        assertTrue("Package should remain whitelisted: " + TEST_PACKAGE_NAME,
-                mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME));
-        assertFalse("Package should no longer be whitelisted: " + TEST_PACKAGE_NAME_2,
-                mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
+        // Assert the new allowlist is applied
+        assertTrue("Package should remain allowlisted: " + TEST_PACKAGE_NAME,
+                mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME));
+        assertFalse("Package should no longer be allowlisted: " + TEST_PACKAGE_NAME_2,
+                mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
     }
 
     @Test
     public void testUpdateLockTaskPackages_taskRemoved() throws Exception {
-        // GIVEN two tasks which are whitelisted initially
+        // GIVEN two tasks which are allowlisted initially
         Task tr1 = getTaskForUpdate(TEST_PACKAGE_NAME, true);
         Task tr2 = getTaskForUpdate(TEST_PACKAGE_NAME_2, false);
-        String[] whitelist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
-        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+        String[] allowlist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
 
         // GIVEN the tasks are launched into LockTask mode
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -548,9 +548,9 @@
         assertTrue(mLockTaskController.isTaskLocked(tr2));
         verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
 
-        // WHEN removing one package from whitelist
-        whitelist = new String[] {TEST_PACKAGE_NAME};
-        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+        // WHEN removing one package from allowlist
+        allowlist = new String[] {TEST_PACKAGE_NAME};
+        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
 
         // THEN the task running that package should be stopped
         verify(tr2).performClearTaskLocked();
@@ -560,9 +560,9 @@
         assertTrue(mLockTaskController.isTaskLocked(tr1));
         verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
 
-        // WHEN removing the last package from whitelist
-        whitelist = new String[] {};
-        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+        // WHEN removing the last package from allowlist
+        allowlist = new String[] {};
+        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
 
         // THEN the last task should be cleared, and the system should quit LockTask mode
         verify(tr1).performClearTaskLocked();
@@ -574,7 +574,7 @@
     @Test
     public void testUpdateLockTaskFeatures() throws Exception {
         // GIVEN a locked task
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN lock task mode should be started with default status bar masks
@@ -616,7 +616,7 @@
     @Test
     public void testUpdateLockTaskFeatures_differentUser() throws Exception {
         // GIVEN a locked task
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN lock task mode should be started with default status bar masks
@@ -638,7 +638,7 @@
     @Test
     public void testUpdateLockTaskFeatures_keyguard() {
         // GIVEN a locked task
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN keyguard should be disabled
@@ -704,7 +704,7 @@
                 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
 
         // Start lock task mode
-        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled
@@ -719,15 +719,15 @@
         assertTrue(mLockTaskController.isActivityAllowed(
                 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_ALWAYS));
 
-        // unwhitelisted package should not be allowed
+        // unallowlisted package should not be allowed
         assertFalse(mLockTaskController.isActivityAllowed(
                 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
 
-        // update the whitelist
-        String[] whitelist = new String[] { TEST_PACKAGE_NAME };
-        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+        // update the allowlist
+        String[] allowlist = new String[] { TEST_PACKAGE_NAME };
+        mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
 
-        // whitelisted package should be allowed
+        // allowlisted package should be allowed
         assertTrue(mLockTaskController.isActivityAllowed(
                 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
 
@@ -755,17 +755,17 @@
     }
 
     /**
-     * @param isAppAware {@code true} if the app has marked if_whitelisted in its manifest
+     * @param isAppAware {@code true} if the app has marked if allowlisted in its manifest
      */
     private Task getTaskForUpdate(String pkg, boolean isAppAware) {
-        final int authIfWhitelisted = isAppAware
+        final int authIfAllowlisted = isAppAware
                 ? Task.LOCK_TASK_AUTH_LAUNCHABLE
-                : Task.LOCK_TASK_AUTH_WHITELISTED;
-        Task tr = getTask(pkg, authIfWhitelisted);
+                : Task.LOCK_TASK_AUTH_ALLOWLISTED;
+        Task tr = getTask(pkg, authIfAllowlisted);
         doAnswer((invocation) -> {
-            boolean isWhitelisted =
-                    mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg);
-            tr.mLockTaskAuth = isWhitelisted ? authIfWhitelisted : Task.LOCK_TASK_AUTH_PINNABLE;
+            boolean isAllowlisted =
+                    mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg);
+            tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : Task.LOCK_TASK_AUTH_PINNABLE;
             return null;
         }).when(tr).setLockTaskAuth();
         return tr;
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 1724303..54c7f27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -94,7 +94,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class RecentTasksTest extends ActivityTestsBase {
+public class RecentTasksTest extends WindowTestsBase {
     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;
@@ -122,14 +122,14 @@
         mTaskContainer = mRootWindowContainer.getDefaultTaskDisplayArea();
 
         // Set the recent tasks we should use for testing in this class.
-        mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
+        mRecentTasks = new TestRecentTasks(mAtm, mTaskPersister);
         spyOn(mRecentTasks);
-        mService.setRecentTasks(mRecentTasks);
+        mAtm.setRecentTasks(mRecentTasks);
         mRecentTasks.loadParametersFromResources(mContext.getResources());
 
         // Set the running tasks we should use for testing in this class.
         mRunningTasks = new TestRunningTasks();
-        mService.mStackSupervisor.setRunningTasks(mRunningTasks);
+        mAtm.mStackSupervisor.setRunningTasks(mRunningTasks);
 
         mStack = mTaskContainer.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -455,7 +455,7 @@
         final Function<Boolean, Task> taskBuilder = visible -> {
             final Task task = createTaskBuilder(className).build();
             // Make the task non-empty.
-            final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
+            final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
             r.setVisibility(visible);
             return task;
         };
@@ -831,7 +831,7 @@
 
         Task stack = mTasks.get(2).getRootTask();
         stack.moveToFront("", mTasks.get(2));
-        doReturn(stack).when(mService.mRootWindowContainer).getTopDisplayFocusedStack();
+        doReturn(stack).when(mAtm.mRootWindowContainer).getTopDisplayFocusedStack();
 
         // Simulate the reset from the timeout
         mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
@@ -994,16 +994,16 @@
         mStack.removeIfPossible();
 
         // The following APIs should not restore task from recents to the active list.
-        assertNotRestoreTask(() -> mService.setFocusedTask(taskId));
-        assertNotRestoreTask(() -> mService.startSystemLockTaskMode(taskId));
-        assertNotRestoreTask(() -> mService.cancelTaskWindowTransition(taskId));
+        assertNotRestoreTask(() -> mAtm.setFocusedTask(taskId));
+        assertNotRestoreTask(() -> mAtm.startSystemLockTaskMode(taskId));
+        assertNotRestoreTask(() -> mAtm.cancelTaskWindowTransition(taskId));
         assertNotRestoreTask(
-                () -> mService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
+                () -> mAtm.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
         assertNotRestoreTask(
-                () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
+                () -> mAtm.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
                         false/* toTop */));
         assertNotRestoreTask(
-                () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId, false /* toTop */));
+                () -> mAtm.setTaskWindowingModeSplitScreenPrimary(taskId, false /* toTop */));
     }
 
     @Test
@@ -1014,7 +1014,7 @@
         mRecentTasks.remove(task);
 
         TaskChangeNotificationController controller =
-                mService.getTaskChangeNotificationController();
+                mAtm.getTaskChangeNotificationController();
         verify(controller, times(2)).notifyTaskListUpdated();
     }
 
@@ -1027,7 +1027,7 @@
 
         // 2 calls - Once for add and once for remove
         TaskChangeNotificationController controller =
-                mService.getTaskChangeNotificationController();
+                mAtm.getTaskChangeNotificationController();
         verify(controller, times(2)).notifyTaskListUpdated();
     }
 
@@ -1042,7 +1042,7 @@
 
         // 4 calls - Twice for add and twice for remove
         TaskChangeNotificationController controller =
-                mService.getTaskChangeNotificationController();
+                mAtm.getTaskChangeNotificationController();
         verify(controller, times(4)).notifyTaskListUpdated();
     }
 
@@ -1054,7 +1054,7 @@
         final Bundle data = new Bundle();
         data.putInt("key", 100);
         final Task task1 = createTaskBuilder(".Task").build();
-        final ActivityRecord r1 = new ActivityBuilder(mService)
+        final ActivityRecord r1 = new ActivityBuilder(mAtm)
                 .setTask(task1)
                 .setIntentExtras(data)
                 .build();
@@ -1106,7 +1106,7 @@
 
     @Test
     public void testNotRecentsComponent_denyApiAccess() throws Exception {
-        doReturn(PackageManager.PERMISSION_DENIED).when(mService)
+        doReturn(PackageManager.PERMISSION_DENIED).when(mAtm)
                 .checkGetTasksPermission(anyString(), anyInt(), anyInt());
         // Expect the following methods to fail due to recents component not being set
         mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
@@ -1118,7 +1118,7 @@
 
     @Test
     public void testRecentsComponent_allowApiAccessWithoutPermissions() {
-        doReturn(PackageManager.PERMISSION_DENIED).when(mService)
+        doReturn(PackageManager.PERMISSION_DENIED).when(mAtm)
                 .checkGetTasksPermission(anyString(), anyInt(), anyInt());
         // Set the recents component and ensure that the following calls do not fail
         mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
@@ -1127,50 +1127,50 @@
     }
 
     private void doTestRecentTasksApis(boolean expectCallable) {
-        assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID));
+        assertSecurityException(expectCallable, () -> mAtm.removeStack(INVALID_STACK_ID));
         assertSecurityException(expectCallable,
-                () -> mService.removeStacksInWindowingModes(
+                () -> mAtm.removeStacksInWindowingModes(
                         new int[]{WINDOWING_MODE_UNDEFINED}));
         assertSecurityException(expectCallable,
-                () -> mService.removeStacksWithActivityTypes(
+                () -> mAtm.removeStacksWithActivityTypes(
                         new int[]{ACTIVITY_TYPE_UNDEFINED}));
-        assertSecurityException(expectCallable, () -> mService.removeTask(0));
+        assertSecurityException(expectCallable, () -> mAtm.removeTask(0));
         assertSecurityException(expectCallable,
-                () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
+                () -> mAtm.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
         assertSecurityException(expectCallable,
-                () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
+                () -> mAtm.moveTaskToStack(0, INVALID_STACK_ID, true));
         assertSecurityException(expectCallable,
-                () -> mService.setTaskWindowingModeSplitScreenPrimary(0, true));
+                () -> mAtm.setTaskWindowingModeSplitScreenPrimary(0, true));
         assertSecurityException(expectCallable,
-                () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
-        assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
+                () -> mAtm.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
+        assertSecurityException(expectCallable, () -> mAtm.getAllStackInfos());
         assertSecurityException(expectCallable,
-                () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
+                () -> mAtm.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
         assertSecurityException(expectCallable, () -> {
             try {
-                mService.getFocusedStackInfo();
+                mAtm.getFocusedStackInfo();
             } catch (RemoteException e) {
                 // Ignore
             }
         });
         assertSecurityException(expectCallable,
-                () -> mService.startActivityFromRecents(0, new Bundle()));
-        assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true));
-        assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null));
+                () -> mAtm.startActivityFromRecents(0, new Bundle()));
+        assertSecurityException(expectCallable, () -> mAtm.getTaskSnapshot(0, true));
+        assertSecurityException(expectCallable, () -> mAtm.registerTaskStackListener(null));
         assertSecurityException(expectCallable,
-                () -> mService.unregisterTaskStackListener(null));
-        assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
-        assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
-        assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
+                () -> mAtm.unregisterTaskStackListener(null));
+        assertSecurityException(expectCallable, () -> mAtm.getTaskDescription(0));
+        assertSecurityException(expectCallable, () -> mAtm.cancelTaskWindowTransition(0));
+        assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, null,
                 null));
-        assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
-        assertSecurityException(expectCallable, () -> mService.stopAppSwitches());
-        assertSecurityException(expectCallable, () -> mService.resumeAppSwitches());
+        assertSecurityException(expectCallable, () -> mAtm.cancelRecentsAnimation(true));
+        assertSecurityException(expectCallable, () -> mAtm.stopAppSwitches());
+        assertSecurityException(expectCallable, () -> mAtm.resumeAppSwitches());
     }
 
     private void testGetTasksApis(boolean expectCallable) {
-        mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
-        mService.getTasks(MAX_VALUE);
+        mAtm.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
+        mAtm.getTasks(MAX_VALUE);
         if (expectCallable) {
             assertTrue(mRecentTasks.mLastAllowed);
             assertTrue(mRunningTasks.mLastAllowed);
@@ -1185,7 +1185,7 @@
     }
 
     private TaskBuilder createTaskBuilder(String packageName, String className) {
-        return new TaskBuilder(mService.mStackSupervisor)
+        return new TaskBuilder(mAtm.mStackSupervisor)
                 .setComponent(new ComponentName(packageName, className))
                 .setStack(mStack)
                 .setUserId(TEST_USER_0_ID);
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 8bc8c0b..7fb7d40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -477,7 +477,7 @@
     }
 
     private ActivityRecord createHomeActivity() {
-        final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+        final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
                 .setStack(mRootHomeTask)
                 .setCreateTask(true)
                 .build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index e5d1e46..d821d38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -66,7 +66,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class RecentsAnimationTest extends ActivityTestsBase {
+public class RecentsAnimationTest extends WindowTestsBase {
 
     private static final int TEST_USER_ID = 100;
 
@@ -77,11 +77,11 @@
     @Before
     public void setUp() throws Exception {
         mRecentsAnimationController = mock(RecentsAnimationController.class);
-        mService.mWindowManager.setRecentsAnimationController(mRecentsAnimationController);
-        doNothing().when(mService.mWindowManager).initializeRecentsAnimation(
+        mAtm.mWindowManager.setRecentsAnimationController(mRecentsAnimationController);
+        doNothing().when(mAtm.mWindowManager).initializeRecentsAnimation(
                 anyInt(), any(), any(), anyInt(), any(), any());
 
-        final RecentTasks recentTasks = mService.getRecentTasks();
+        final RecentTasks recentTasks = mAtm.getRecentTasks();
         spyOn(recentTasks);
         doReturn(mRecentsComponent).when(recentTasks).getRecentsComponent();
     }
@@ -91,12 +91,12 @@
         TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
-        ActivityRecord recentActivity = new ActivityBuilder(mService)
+        ActivityRecord recentActivity = new ActivityBuilder(mAtm)
                 .setComponent(mRecentsComponent)
                 .setCreateTask(true)
                 .setStack(recentsStack)
                 .build();
-        ActivityRecord topActivity = new ActivityBuilder(mService).setCreateTask(true).build();
+        ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
         topActivity.getRootTask().moveToFront("testRecentsActivityVisiblility");
 
         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
@@ -123,7 +123,7 @@
                 false /* includingParents */);
         ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
         if (topRunningHomeActivity == null) {
-            topRunningHomeActivity = new ActivityBuilder(mService)
+            topRunningHomeActivity = new ActivityBuilder(mAtm)
                     .setStack(homeStack)
                     .setCreateTask(true)
                     .build();
@@ -139,15 +139,15 @@
                 anyInt() /* startFlags */, any() /* profilerInfo */);
 
         // Assume its process is alive because the caller should be the recents service.
-        WindowProcessController wpc = new WindowProcessController(mService, aInfo.applicationInfo,
+        WindowProcessController wpc = new WindowProcessController(mAtm, aInfo.applicationInfo,
                 aInfo.processName, aInfo.applicationInfo.uid, 0 /* userId */,
                 mock(Object.class) /* owner */, mock(WindowProcessListener.class));
         wpc.setThread(mock(IApplicationThread.class));
-        doReturn(wpc).when(mService).getProcessController(eq(wpc.mName), eq(wpc.mUid));
+        doReturn(wpc).when(mAtm).getProcessController(eq(wpc.mName), eq(wpc.mUid));
 
         Intent recentsIntent = new Intent().setComponent(mRecentsComponent);
         // Null animation indicates to preload.
-        mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+        mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
                 null /* recentsAnimationRunner */);
 
         Task recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN,
@@ -167,7 +167,7 @@
 
         spyOn(recentsActivity);
         // Start when the recents activity exists. It should ensure the configuration.
-        mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+        mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
                 null /* recentsAnimationRunner */);
 
         verify(recentsActivity).ensureActivityConfiguration(anyInt() /* globalChanges */,
@@ -181,20 +181,20 @@
         TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         Task recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
-        ActivityRecord recentActivity = new ActivityBuilder(mService).setComponent(
+        ActivityRecord recentActivity = new ActivityBuilder(mAtm).setComponent(
                 mRecentsComponent).setCreateTask(true).setStack(recentsStack).build();
         WindowProcessController app = recentActivity.app;
         recentActivity.app = null;
 
         // Start an activity on top.
-        new ActivityBuilder(mService).setCreateTask(true).build().getRootTask().moveToFront(
+        new ActivityBuilder(mAtm).setCreateTask(true).build().getRootTask().moveToFront(
                 "testRestartRecentsActivity");
 
         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
                 any() /* starting */, anyInt() /* configChanges */,
                 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
-        doReturn(app).when(mService).getProcessController(eq(recentActivity.processName), anyInt());
-        ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+        doReturn(app).when(mAtm).getProcessController(eq(recentActivity.processName), anyInt());
+        ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
         doNothing().when(lifecycleManager).scheduleTransaction(any());
 
         startRecentsActivity();
@@ -212,20 +212,20 @@
         // Assume the home activity support recents.
         ActivityRecord targetActivity = homeStack.getTopNonFinishingActivity();
         if (targetActivity == null) {
-            targetActivity = new ActivityBuilder(mService)
+            targetActivity = new ActivityBuilder(mAtm)
                     .setCreateTask(true)
                     .setStack(homeStack)
                     .build();
         }
 
         // Put another home activity in home stack.
-        ActivityRecord anotherHomeActivity = new ActivityBuilder(mService)
+        ActivityRecord anotherHomeActivity = new ActivityBuilder(mAtm)
                 .setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
                 .setCreateTask(true)
                 .setStack(homeStack)
                 .build();
         // Start an activity on top so the recents activity can be started.
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .build()
                 .getRootTask()
@@ -252,21 +252,21 @@
         TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setComponent(new ComponentName(mContext.getPackageName(), "App1"))
                 .setCreateTask(true)
                 .setStack(fullscreenStack)
                 .build();
         Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setComponent(mRecentsComponent)
                 .setCreateTask(true)
                 .setStack(recentsStack)
                 .build();
         Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setComponent(new ComponentName(mContext.getPackageName(), "App2"))
                 .setCreateTask(true)
                 .setStack(fullscreenStack2)
@@ -293,21 +293,21 @@
         TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setComponent(new ComponentName(mContext.getPackageName(), "App1"))
                 .setCreateTask(true)
                 .setStack(fullscreenStack)
                 .build();
         Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setComponent(mRecentsComponent)
                 .setCreateTask(true)
                 .setStack(recentsStack)
                 .build();
         Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setComponent(new ComponentName(mContext.getPackageName(), "App2"))
                 .setCreateTask(true)
                 .setStack(fullscreenStack2)
@@ -319,7 +319,7 @@
         fullscreenStack.removeIfPossible();
 
         // Ensure that the recents animation was NOT canceled
-        verify(mService.mWindowManager, times(0)).cancelRecentsAnimation(
+        verify(mAtm.mWindowManager, times(0)).cancelRecentsAnimation(
                 eq(REORDER_KEEP_IN_PLACE), any());
         verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
     }
@@ -330,7 +330,7 @@
                 .getDefaultTaskDisplayArea();
         Task homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
                 ACTIVITY_TYPE_HOME);
-        ActivityRecord otherUserHomeActivity = new ActivityBuilder(mService)
+        ActivityRecord otherUserHomeActivity = new ActivityBuilder(mAtm)
                 .setStack(homeStack)
                 .setCreateTask(true)
                 .setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
@@ -339,13 +339,13 @@
 
         Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        new ActivityBuilder(mService)
+        new ActivityBuilder(mAtm)
                 .setComponent(new ComponentName(mContext.getPackageName(), "App1"))
                 .setCreateTask(true)
                 .setStack(fullscreenStack)
                 .build();
 
-        doReturn(TEST_USER_ID).when(mService).getCurrentUserId();
+        doReturn(TEST_USER_ID).when(mAtm).getCurrentUserId();
         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
                 any() /* starting */, anyInt() /* configChanges */,
                 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
@@ -373,7 +373,7 @@
                 // The callback is actually RecentsAnimation.
                 recentsAnimation[0] = invocation.getArgument(2);
                 return null;
-            }).when(mService.mWindowManager).initializeRecentsAnimation(
+            }).when(mAtm.mWindowManager).initializeRecentsAnimation(
                     anyInt() /* targetActivityType */, any() /* recentsAnimationRunner */,
                     any() /* callbacks */, anyInt() /* displayId */, any() /* recentTaskIds */,
                     any() /* targetActivity */);
@@ -381,7 +381,7 @@
 
         Intent recentsIntent = new Intent();
         recentsIntent.setComponent(recentsComponent);
-        mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
+        mAtm.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
                 mock(IRecentsAnimationRunner.class));
         return recentsAnimation[0];
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 74be2c9..1ec9bd2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -89,14 +89,14 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class RootActivityContainerTests extends ActivityTestsBase {
+public class RootActivityContainerTests extends WindowTestsBase {
     private Task mFullscreenStack;
 
     @Before
     public void setUp() throws Exception {
         mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        doNothing().when(mService).updateSleepIfNeededLocked();
+        doNothing().when(mAtm).updateSleepIfNeededLocked();
     }
 
     /**
@@ -117,11 +117,11 @@
      */
     @Test
     public void testReplacingTaskInPinnedStack() {
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
         final Task task = firstActivity.getTask();
 
-        final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task)
                 .setStack(mFullscreenStack).build();
 
         mFullscreenStack.moveToFront("testReplacingTaskInPinnedStack");
@@ -152,11 +152,11 @@
 
     @Test
     public void testMovingBottomMostStackActivityToPinnedStack() {
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
         final Task task = firstActivity.getTask();
 
-        final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task)
                 .setStack(mFullscreenStack).build();
 
         mFullscreenStack.moveTaskToBack(task);
@@ -252,7 +252,7 @@
     @Test
     public void testAwakeFromSleepingWithAppConfiguration() {
         final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
-        final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
         activity.moveFocusableActivityToTop("test");
         assertTrue(activity.getStack().isFocusedStackOnDisplay());
         ActivityRecordTests.setRotatedScreenOrientationSilently(activity);
@@ -264,13 +264,13 @@
         // Assume the activity was shown in different orientation. For example, the top activity is
         // landscape and the portrait lockscreen is shown.
         activity.setLastReportedConfiguration(
-                new MergedConfiguration(mService.getGlobalConfiguration(), rotatedConfig));
+                new MergedConfiguration(mAtm.getGlobalConfiguration(), rotatedConfig));
         activity.setState(ActivityState.STOPPED, "sleep");
 
         display.setIsSleeping(true);
         doReturn(false).when(display).shouldSleep();
         // Allow to resume when awaking.
-        setBooted(mService);
+        setBooted(mAtm);
         mRootWindowContainer.applySleepTokens(true);
 
         // The display orientation should be changed by the activity so there is no relaunch.
@@ -288,7 +288,7 @@
         final int originalStackCount = defaultTaskDisplayArea.getStackCount();
         final Task stack = defaultTaskDisplayArea.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(stack).build();
 
         assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
@@ -312,16 +312,16 @@
         final int originalStackCount = defaultTaskDisplayArea.getStackCount();
         final Task stack = defaultTaskDisplayArea.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
-        final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(stack).build();
         assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
 
         final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
-        final TaskDisplayArea secondTaskDisplayArea = WindowTestsBase.createTaskDisplayArea(dc,
-                mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
+        final TaskDisplayArea secondTaskDisplayArea = WindowTestsBase.createTaskDisplayArea(
+                dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
         final Task secondStack = secondTaskDisplayArea.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
-        new ActivityBuilder(mService).setCreateTask(true).setStack(secondStack)
+        new ActivityBuilder(mAtm).setCreateTask(true).setStack(secondStack)
                 .setUseProcess(firstActivity.app).build();
         assertEquals(1, secondTaskDisplayArea.getStackCount());
 
@@ -340,7 +340,7 @@
                 .getDefaultTaskDisplayArea();
         final Task stack = defaultTaskDisplayArea.createStack(
                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(stack).build();
 
         // Created stacks are focusable by default.
@@ -354,7 +354,7 @@
 
         final Task pinnedStack = defaultTaskDisplayArea.createStack(
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true)
+        final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm).setCreateTask(true)
                 .setStack(pinnedStack).build();
 
         // We should not be focusable when in pinned mode
@@ -385,7 +385,7 @@
                 .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
                         true /* onTop */);
         final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
-        final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
 
         // Find a launch stack for the top activity in split-screen primary, while requesting
         // split-screen secondary.
@@ -439,7 +439,7 @@
         final Task stack = secondDisplay.getDefaultTaskDisplayArea()
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
         final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         final String reason = "findTaskToMoveToFront";
         mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
@@ -459,7 +459,7 @@
         final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
         taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
 
         // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
@@ -489,7 +489,7 @@
 
         doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
 
-        mService.setBooted(true);
+        mAtm.setBooted(true);
 
         // Trigger resume on all displays
         mRootWindowContainer.resumeFocusedStacksTopActivities();
@@ -515,11 +515,11 @@
         final Task stack = secondDisplay.getDefaultTaskDisplayArea()
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
 
-        mService.setBooted(true);
+        mAtm.setBooted(true);
 
         // Trigger resume on all displays
         mRootWindowContainer.resumeFocusedStacksTopActivities();
@@ -539,7 +539,7 @@
         final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
         activity.setState(ActivityState.RESUMED, "test");
 
         // Assume the stack is at the topmost position
@@ -559,7 +559,7 @@
         final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
-        final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
         activity.setState(ActivityState.RESUMED, "test");
         taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
 
@@ -584,7 +584,7 @@
 
         // Create secondary displays.
         final TestDisplayContent secondDisplay =
-                new TestDisplayContent.Builder(mService, 1000, 1500)
+                new TestDisplayContent.Builder(mAtm, 1000, 1500)
                         .setSystemDecorations(true).build();
 
         doReturn(true).when(mRootWindowContainer)
@@ -605,16 +605,16 @@
     @Test
     public void testNotStartHomeBeforeBoot() {
         final int displayId = 1;
-        final boolean isBooting = mService.mAmInternal.isBooting();
-        final boolean isBooted = mService.mAmInternal.isBooted();
+        final boolean isBooting = mAtm.mAmInternal.isBooting();
+        final boolean isBooted = mAtm.mAmInternal.isBooted();
         try {
-            mService.mAmInternal.setBooting(false);
-            mService.mAmInternal.setBooted(false);
+            mAtm.mAmInternal.setBooting(false);
+            mAtm.mAmInternal.setBooted(false);
             mRootWindowContainer.onDisplayAdded(displayId);
             verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
         } finally {
-            mService.mAmInternal.setBooting(isBooting);
-            mService.mAmInternal.setBooted(isBooted);
+            mAtm.mAmInternal.setBooting(isBooting);
+            mAtm.mAmInternal.setBooted(isBooted);
         }
     }
 
@@ -626,7 +626,7 @@
         final ActivityInfo info = new ActivityInfo();
         info.applicationInfo = new ApplicationInfo();
         final WindowProcessController app = mock(WindowProcessController.class);
-        doReturn(app).when(mService).getProcessController(any(), anyInt());
+        doReturn(app).when(mAtm).getProcessController(any(), anyInt());
 
         // Can not start home if we don't want to start home while home is being instrumented.
         doReturn(true).when(app).isInstrumenting();
@@ -653,7 +653,7 @@
     public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
         // Create secondary displays.
         final TestDisplayContent secondDisplay =
-                new TestDisplayContent.Builder(mService, 1000, 1500)
+                new TestDisplayContent.Builder(mAtm, 1000, 1500)
                         .setSystemDecorations(true).build();
 
         // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
@@ -678,7 +678,7 @@
     public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
         // Create secondary displays.
         final TestDisplayContent secondDisplay =
-                new TestDisplayContent.Builder(mService, 1000, 1500)
+                new TestDisplayContent.Builder(mAtm, 1000, 1500)
                         .setSystemDecorations(false).build();
 
         mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
@@ -712,7 +712,7 @@
     @Test
     public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() {
         // Setup: primary home not set.
-        final Intent primaryHomeIntent = mService.getHomeIntent();
+        final Intent primaryHomeIntent = mAtm.getHomeIntent();
         final ActivityInfo aInfoPrimary = new ActivityInfo();
         aInfoPrimary.name = ResolverActivity.class.getName();
         doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
@@ -740,7 +740,7 @@
         // SetUp: set secondary home and force it.
         mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */);
         final Intent secondaryHomeIntent =
-                mService.getSecondaryHomeIntent(null /* preferredPackage */);
+                mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
         final List<ResolveInfo> resolutions = new ArrayList<>();
         final ResolveInfo resolveInfo = new ResolveInfo();
         final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
@@ -855,11 +855,11 @@
     public void testGetLaunchStackWithRealCallerId() {
         // Create a non-system owned virtual display.
         final TestDisplayContent secondaryDisplay =
-                new TestDisplayContent.Builder(mService, 1000, 1500)
+                new TestDisplayContent.Builder(mAtm, 1000, 1500)
                         .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
 
         // Create an activity with specify the original launch pid / uid.
-        final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200)
+        final ActivityRecord r = new ActivityBuilder(mAtm).setLaunchedFromPid(200)
                 .setLaunchedFromUid(200).build();
 
         // Simulate ActivityStarter to find a launch stack for requesting the activity to launch
@@ -882,12 +882,11 @@
     @Test
     public void testGetValidLaunchStackOnDisplayWithCandidateRootTask() {
         // Create a root task with an activity on secondary display.
-        final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mService, 300,
+        final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
                 600).build();
-        final Task task = new ActivityTestsBase.StackBuilder(mRootWindowContainer).setDisplay(
-                secondaryDisplay).build();
-        final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mService)
-                .setTask(task).build();
+        final Task task = new StackBuilder(mRootWindowContainer)
+                .setDisplay(secondaryDisplay).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
 
         // Make sure the root task is valid and can be reused on default display.
         final Task stack = mRootWindowContainer.getValidLaunchStackInTaskDisplayArea(
@@ -923,7 +922,7 @@
                 DisplayContent.POSITION_TOP);
         final Task stack = secondDisplay.getDefaultTaskDisplayArea()
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final ActivityRecord activity = new ActivityBuilder(mService).setStack(stack).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setStack(stack).build();
         spyOn(activity);
         spyOn(stack);
 
@@ -946,7 +945,7 @@
         ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome);
         Intent targetIntent;
         if (primaryHome) {
-            targetIntent = mService.getHomeIntent();
+            targetIntent = mAtm.getHomeIntent();
         } else {
             Resources resources = mContext.getResources();
             spyOn(resources);
@@ -954,7 +953,7 @@
                     com.android.internal.R.string.config_secondaryHomePackage);
             doReturn(forceSystemProvided).when(resources).getBoolean(
                     com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
-            targetIntent = mService.getSecondaryHomeIntent(null /* preferredPackage */);
+            targetIntent = mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
         }
         doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
                 refEq(targetIntent));
@@ -965,7 +964,7 @@
      * activity info for test cases.
      */
     private void mockResolveSecondaryHomeActivity() {
-        final Intent secondaryHomeIntent = mService
+        final Intent secondaryHomeIntent = mAtm
                 .getSecondaryHomeIntent(null /* preferredPackage */);
         final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false);
         doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 2e4c9ea..72899e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -133,10 +133,10 @@
     @Test
     public void testFindActivityByTargetComponent() {
         final ComponentName aliasComponent = ComponentName.createRelative(
-                ActivityTestsBase.DEFAULT_COMPONENT_PACKAGE_NAME, ".AliasActivity");
+                DEFAULT_COMPONENT_PACKAGE_NAME, ".AliasActivity");
         final ComponentName targetComponent = ComponentName.createRelative(
                 aliasComponent.getPackageName(), ".TargetActivity");
-        final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+        final ActivityRecord activity = new ActivityBuilder(mWm.mAtmService)
                 .setComponent(aliasComponent)
                 .setTargetActivity(targetComponent.getClassName())
                 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
@@ -174,24 +174,29 @@
 
     @Test
     public void testForceStopPackage() {
-        final Task task = new ActivityTestsBase.StackBuilder(mWm.mRoot).build();
-        final ActivityRecord activity1 = task.getTopMostActivity();
-        final ActivityRecord activity2 =
-                new ActivityTestsBase.ActivityBuilder(mWm.mAtmService).setStack(task).build();
-        final WindowProcessController wpc = activity1.app;
+        final Task task = new StackBuilder(mWm.mRoot).build();
+        final ActivityRecord activity = task.getTopMostActivity();
+        final WindowProcessController wpc = activity.app;
+        final ActivityRecord[] activities = {
+                activity,
+                new ActivityBuilder(mWm.mAtmService).setStack(task).setUseProcess(wpc).build(),
+                new ActivityBuilder(mWm.mAtmService).setStack(task).setUseProcess(wpc).build()
+        };
+        activities[0].detachFromProcess();
+        activities[1].finishing = true;
+        activities[1].destroyImmediately(true /* removeFromApp */, "test");
         spyOn(wpc);
-        activity1.app = null;
-        activity2.setProcess(wpc);
         doReturn(true).when(wpc).isRemoved();
 
         mWm.mAtmService.mInternal.onForceStopPackage(wpc.mInfo.packageName, true /* doit */,
                 false /* evenPersistent */, wpc.mUserId);
         // The activity without process should be removed.
-        assertEquals(1, task.getChildCount());
+        assertEquals(2, task.getChildCount());
 
-        mWm.mRoot.handleAppDied(wpc);
-        // The activity with process should be removed because WindowProcessController#isRemoved.
+        wpc.handleAppDied();
+        // The activities with process should be removed because WindowProcessController#isRemoved.
         assertFalse(task.hasChild());
+        assertFalse(wpc.hasActivities());
     }
 }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index e51a133..3415093 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -42,7 +42,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class RunningTasksTest extends ActivityTestsBase {
+public class RunningTasksTest extends WindowTestsBase {
 
     private static final ArraySet<Integer> PROFILE_IDS = new ArraySet<>();
 
@@ -57,7 +57,7 @@
     public void testCollectTasksByLastActiveTime() {
         // Create a number of stacks with tasks (of incrementing active time)
         final ArrayList<DisplayContent> displays = new ArrayList<>();
-        final DisplayContent display = new TestDisplayContent.Builder(mService, 1000, 2500).build();
+        final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
         displays.add(display);
 
         final int numStacks = 2;
@@ -101,7 +101,7 @@
 
     @Test
     public void testTaskInfo_expectNoExtras() {
-        final DisplayContent display = new TestDisplayContent.Builder(mService, 1000, 2500).build();
+        final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
         final int numTasks = 10;
         for (int i = 0; i < numTasks; i++) {
             final Task stack = new StackBuilder(mRootWindowContainer)
@@ -132,13 +132,13 @@
      */
     private Task createTask(Task stack, String className, int taskId,
             int lastActiveTime, Bundle extras) {
-        final Task task = new TaskBuilder(mService.mStackSupervisor)
+        final Task task = new TaskBuilder(mAtm.mStackSupervisor)
                 .setComponent(new ComponentName(mContext.getPackageName(), className))
                 .setTaskId(taskId)
                 .setStack(stack)
                 .build();
         task.lastActiveTime = lastActiveTime;
-        final ActivityRecord activity = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setTask(task)
                 .setComponent(new ComponentName(mContext.getPackageName(), ".TaskActivity"))
                 .setIntentExtras(extras)
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 250cf09..0e1d4dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -64,7 +64,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class SizeCompatTests extends ActivityTestsBase {
+public class SizeCompatTests extends WindowTestsBase {
     private Task mStack;
     private Task mTask;
     private ActivityRecord mActivity;
@@ -76,7 +76,7 @@
     }
 
     private void setUpDisplaySizeWithApp(int dw, int dh) {
-        final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mService, dw, dh);
+        final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mAtm, dw, dh);
         setUpApp(builder.build());
     }
 
@@ -92,7 +92,7 @@
         final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
         resizeDisplay(mStack.getDisplay(), 600, 1200);
         // The visible activity should recompute configuration according to the last parent bounds.
-        mService.restartActivityProcessIfVisible(mActivity.appToken);
+        mAtm.restartActivityProcessIfVisible(mActivity.appToken);
 
         assertEquals(Task.ActivityState.RESTARTING_PROCESS, mActivity.getState());
         assertNotEquals(originalOverrideBounds, mActivity.getBounds());
@@ -102,7 +102,7 @@
     public void testKeepBoundsWhenChangingFromFreeformToFullscreen() {
         removeGlobalMinSizeRestriction();
         // create freeform display and a freeform app
-        DisplayContent display = new TestDisplayContent.Builder(mService, 2000, 1000)
+        DisplayContent display = new TestDisplayContent.Builder(mAtm, 2000, 1000)
                 .setCanRotate(false)
                 .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM).build();
         setUpApp(display);
@@ -135,7 +135,7 @@
     @Test
     public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() {
         final int notchHeight = 100;
-        setUpApp(new TestDisplayContent.Builder(mService, 600, 800).setNotch(notchHeight).build());
+        setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800).setNotch(notchHeight).build());
         // Rotation is ignored so because the display size is close to square (700/600<1.333).
         assertTrue(mActivity.mDisplayContent.ignoreRotationForApps());
 
@@ -186,10 +186,10 @@
 
         // Make a new less-tall display with lower density
         final DisplayContent newDisplay =
-                new TestDisplayContent.Builder(mService, 1000, 2000)
+                new TestDisplayContent.Builder(mAtm, 1000, 2000)
                         .setDensityDpi(200).build();
 
-        mActivity = new ActivityBuilder(mService)
+        mActivity = new ActivityBuilder(mAtm)
                 .setTask(mTask)
                 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                 .setMaxAspectRatio(1.5f)
@@ -262,7 +262,7 @@
 
     @Test
     public void testAspectRatioMatchParentBoundsAndImeAttachable() {
-        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2000)
+        setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2000)
                 .setSystemDecorations(true).build());
         prepareUnresizable(2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
         assertFitted();
@@ -293,7 +293,7 @@
         final int origHeight = configBounds.height();
 
         final int notchHeight = 100;
-        final DisplayContent newDisplay = new TestDisplayContent.Builder(mService, 2000, 1000)
+        final DisplayContent newDisplay = new TestDisplayContent.Builder(mAtm, 2000, 1000)
                 .setCanRotate(false).setNotch(notchHeight).build();
 
         // Move the non-resizable activity to the new display.
@@ -327,7 +327,7 @@
     public void testFixedOrientRotateCutoutDisplay() {
         // Create a display with a notch/cutout
         final int notchHeight = 60;
-        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500)
+        setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2500)
                 .setNotch(notchHeight).build());
         // Bounds=[0, 0 - 1000, 1460], AppBounds=[0, 60 - 1000, 1460].
         prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
@@ -430,14 +430,14 @@
         // Change display density
         display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity);
         display.computeScreenConfiguration(rotatedConfig);
-        mService.mAmInternal = mock(ActivityManagerInternal.class);
+        mAtm.mAmInternal = mock(ActivityManagerInternal.class);
         display.onRequestedOverrideConfigurationChanged(rotatedConfig);
 
         // The override configuration should be reset and the activity's process will be killed.
         assertFitted();
         verify(mActivity).restartProcessIfVisible();
-        waitHandlerIdle(mService.mH);
-        verify(mService.mAmInternal).killProcess(
+        waitHandlerIdle(mAtm.mH);
+        verify(mAtm.mAmInternal).killProcess(
                 eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
     }
 
@@ -454,7 +454,7 @@
         assertFitted();
 
         final ArrayList<IBinder> compatTokens = new ArrayList<>();
-        mService.getTaskChangeNotificationController().registerTaskStackListener(
+        mAtm.getTaskChangeNotificationController().registerTaskStackListener(
                 new TaskStackListener() {
                     @Override
                     public void onSizeCompatModeActivityChanged(int displayId,
@@ -492,7 +492,7 @@
         mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
 
         // Create a size compat activity on the same task.
-        final ActivityRecord activity = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setTask(mTask)
                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
                 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
@@ -516,7 +516,7 @@
         final int dw = 1000;
         final int dh = 2500;
         final int notchHeight = 200;
-        setUpApp(new TestDisplayContent.Builder(mService, dw, dh).setNotch(notchHeight).build());
+        setUpApp(new TestDisplayContent.Builder(mAtm, dw, dh).setNotch(notchHeight).build());
         addStatusBar(mActivity.mDisplayContent);
 
         mActivity.setVisible(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 27a8fc3..3492556 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -219,8 +219,7 @@
         final Task rootHomeTask = defaultTaskDisplayArea.getRootHomeTask();
         rootHomeTask.mResizeMode = RESIZE_MODE_UNRESIZEABLE;
 
-        final Task primarySplitTask =
-                new ActivityTestsBase.StackBuilder(rootWindowContainer)
+        final Task primarySplitTask = new StackBuilder(rootWindowContainer)
                 .setTaskDisplayArea(defaultTaskDisplayArea)
                 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
                 .setActivityType(ACTIVITY_TYPE_STANDARD)
@@ -234,7 +233,7 @@
 
         ActivityRecord homeActivity = rootHomeTask.getTopNonFinishingActivity();
         if (homeActivity == null) {
-            homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+            homeActivity = new ActivityBuilder(mWm.mAtmService)
                     .setStack(rootHomeTask).setCreateTask(true).build();
         }
         homeActivity.setVisible(false);
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 a048526..42de5e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -67,7 +67,7 @@
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
+public class TaskLaunchParamsModifierTests extends WindowTestsBase {
     private static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0,
             /* right */ 1920, /* bottom */ 1080);
     private static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100,
@@ -82,7 +82,7 @@
 
     @Before
     public void setUp() throws Exception {
-        mActivity = new ActivityBuilder(mService).build();
+        mActivity = new ActivityBuilder(mAtm).build();
         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
 
@@ -449,7 +449,7 @@
 
     @Test
     public void testForceMaximizesUnresizeableApp() {
-        mService.mSizeCompatFreeform = false;
+        mAtm.mSizeCompatFreeform = false;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
@@ -472,7 +472,7 @@
 
     @Test
     public void testLaunchesAppInWindowOnFreeformDisplay() {
-        mService.mSizeCompatFreeform = true;
+        mAtm.mSizeCompatFreeform = true;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
@@ -1318,18 +1318,18 @@
 
     @Test
     public void testNoMultiDisplaySupports() {
-        final boolean orgValue = mService.mSupportsMultiDisplay;
+        final boolean orgValue = mAtm.mSupportsMultiDisplay;
         final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
         mCurrent.mPreferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
 
         try {
-            mService.mSupportsMultiDisplay = false;
+            mAtm.mSupportsMultiDisplay = false;
             assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
                     mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
             assertEquals(mRootWindowContainer.getDefaultTaskDisplayArea(),
                     mResult.mPreferredTaskDisplayArea);
         } finally {
-            mService.mSupportsMultiDisplay = orgValue;
+            mAtm.mSupportsMultiDisplay = orgValue;
         }
     }
 
@@ -1351,7 +1351,7 @@
     private ActivityRecord createSourceActivity(TestDisplayContent display) {
         final Task stack = display.getDefaultTaskDisplayArea()
                 .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
-        return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
+        return new ActivityBuilder(mAtm).setStack(stack).setCreateTask(true).build();
     }
 
     private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 0db3f94..27cae2f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -77,7 +77,7 @@
         removeGlobalMinSizeRestriction();
 
         final Task stack = createTaskStackOnDisplay(mDisplayContent);
-        final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+        final ActivityRecord activity = new ActivityBuilder(stack.mAtmService)
                 .setStack(stack)
                 // In real case, there is no additional level for freeform mode.
                 .setCreateTask(false)
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 bf76c8e..fc54e1d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -95,7 +95,7 @@
 @MediumTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class TaskRecordTests extends ActivityTestsBase {
+public class TaskRecordTests extends WindowTestsBase {
 
     private static final String TASK_TAG = "task";
 
@@ -172,7 +172,7 @@
     @Test
     public void testFitWithinBounds() {
         final Rect parentBounds = new Rect(10, 10, 200, 200);
-        TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+        TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
         Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -210,7 +210,7 @@
     /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
     @Test
     public void testBoundsOnModeChangeFreeformToFullscreen() {
-        DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
+        DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
         Task stack = new StackBuilder(mRootWindowContainer).setDisplay(display)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         Task task = stack.getBottomMostTask();
@@ -243,7 +243,7 @@
     public void testFullscreenBoundsForcedOrientation() {
         final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
         final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
-        final DisplayContent display = new TestDisplayContent.Builder(mService,
+        final DisplayContent display = new TestDisplayContent.Builder(mAtm,
                 fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
         assertTrue(mRootWindowContainer.getDisplayContent(display.mDisplayId) != null);
         // Fix the display orientation to landscape which is the natural rotation (0) for the test
@@ -267,7 +267,7 @@
         assertEquals(fullScreenBounds.height(), task.getBounds().height());
 
         // Top activity gets used
-        ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
+        ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setStack(stack).build();
         assertEquals(top, task.getTopNonFinishingActivity());
         top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
         assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
@@ -307,7 +307,7 @@
     public void testIgnoresForcedOrientationWhenParentHandles() {
         final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
         DisplayContent display = new TestDisplayContent.Builder(
-                mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
+                mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
 
         display.getRequestedOverrideConfiguration().orientation =
                 Configuration.ORIENTATION_LANDSCAPE;
@@ -339,7 +339,7 @@
     public void testComputeConfigResourceOverrides() {
         final Rect fullScreenBounds = new Rect(0, 0, 1080, 1920);
         TestDisplayContent display = new TestDisplayContent.Builder(
-                mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
+                mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
         final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
         final Configuration inOutConfig = new Configuration();
         final Configuration parentConfig = new Configuration();
@@ -438,11 +438,11 @@
 
     @Test
     public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
-        TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+        TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
         Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         DisplayInfo displayInfo = new DisplayInfo();
-        mService.mContext.getDisplay().getDisplayInfo(displayInfo);
+        mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
         final int displayHeight = displayInfo.logicalHeight;
         final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
         final Configuration inOutConfig = new Configuration();
@@ -514,23 +514,23 @@
         info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
         info.targetActivity = targetClassName;
 
-        final Task task = new Task(mService, 1 /* taskId */, info, intent,
+        final Task task = new Task(mAtm, 1 /* taskId */, info, intent,
                 null /* voiceSession */, null /* voiceInteractor */, null /* taskDescriptor */,
                 null /*stack*/);
         assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
                 task.intent.getComponent().getClassName());
 
-        ActivityRecord aliasActivity = new ActivityBuilder(mService).setComponent(
+        ActivityRecord aliasActivity = new ActivityBuilder(mAtm).setComponent(
                 aliasComponent).setTargetActivity(targetClassName).build();
         assertEquals("Should be the same intent filter.", true,
                 task.isSameIntentFilter(aliasActivity));
 
-        ActivityRecord targetActivity = new ActivityBuilder(mService).setComponent(
+        ActivityRecord targetActivity = new ActivityBuilder(mAtm).setComponent(
                 targetComponent).build();
         assertEquals("Should be the same intent filter.", true,
                 task.isSameIntentFilter(targetActivity));
 
-        ActivityRecord defaultActivity = new ActivityBuilder(mService).build();
+        ActivityRecord defaultActivity = new ActivityBuilder(mAtm).build();
         assertEquals("Should not be the same intent filter.", false,
                 task.isSameIntentFilter(defaultActivity));
     }
@@ -540,7 +540,7 @@
     public void testFindRootIndex() {
         final Task task = getTestTask();
         // Add an extra activity on top of the root one
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.", task.getChildAt(0),
                 task.getRootActivity(
@@ -557,9 +557,9 @@
         // Add extra two activities and mark the two on the bottom as finishing.
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.finishing = true;
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The first non-finishing activity in the task must be reported.",
                 task.getChildAt(2), task.getRootActivity(
@@ -574,7 +574,7 @@
     public void testFindRootIndex_effectiveRoot() {
         final Task task = getTestTask();
         // Add an extra activity on top of the root one
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.",
                 task.getChildAt(0), task.getRootActivity(
@@ -592,9 +592,9 @@
         // one above as finishing.
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.finishing = true;
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The first non-finishing activity and non-relinquishing task identity "
                 + "must be reported.", task.getChildAt(2), task.getRootActivity(
@@ -626,7 +626,7 @@
         // Set relinquishTaskIdentity for all activities in the task
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
 
         assertEquals("The topmost activity in the task must be reported.",
@@ -639,7 +639,7 @@
     public void testGetRootActivity() {
         final Task task = getTestTask();
         // Add an extra activity on top of the root one
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.",
                 task.getBottomMostActivity(), task.getRootActivity());
@@ -652,7 +652,7 @@
     public void testGetRootActivity_finishing() {
         final Task task = getTestTask();
         // Add an extra activity on top of the root one
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
         // Mark the root as finishing
         task.getBottomMostActivity().finishing = true;
 
@@ -670,7 +670,7 @@
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         // Add an extra activity on top of the root one.
-        new ActivityBuilder(mService).setTask(task).build();
+        new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.",
                 task.getBottomMostActivity(), task.getRootActivity());
@@ -687,7 +687,7 @@
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top of the root one and mark it as finishing
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.finishing = true;
 
         assertNull("No activity must be reported if all are finishing", task.getRootActivity());
@@ -703,7 +703,7 @@
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top of the root one.
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
 
         assertFalse("Finishing activity must not be the root of task", activity0.isRootOfTask());
         assertTrue("Non-finishing activity must be the root of task", activity1.isRootOfTask());
@@ -720,7 +720,7 @@
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top of the root one and mark it as finishing
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.finishing = true;
 
         assertTrue("Bottom activity must be the root of task", activity0.isRootOfTask());
@@ -756,9 +756,9 @@
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top - this will be the new root
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         // Add one more on top
-        final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals(task.mTaskId,
                 ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
@@ -779,9 +779,9 @@
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         // Add an extra activity on top - this will be the new root
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         // Add one more on top
-        final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals(task.mTaskId,
                 ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
@@ -803,11 +803,11 @@
         activity0.finishing = true;
 
         // Add an extra activity on top of the root one and make it relinquish task identity
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
 
         // Add one more activity on top
-        final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals(task.mTaskId,
                 ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
@@ -843,7 +843,7 @@
         // Mark the bottom-most activity as finishing.
         activity0.finishing = true;
         // Add an extra activity on top of the root one
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
 
         spyOn(task);
         task.updateEffectiveIntent();
@@ -863,7 +863,7 @@
         // Mark the bottom-most activity as finishing.
         activity0.finishing = true;
         // Add an extra activity on top of the root one and make it relinquish task identity
-        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
         activity1.finishing = true;
 
         // Task must still update the intent using the root activity (preserving legacy behavior).
@@ -874,7 +874,7 @@
 
     @Test
     public void testSaveLaunchingStateWhenConfigurationChanged() {
-        LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+        LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
         spyOn(persister);
 
         final Task task = getTestTask();
@@ -890,7 +890,7 @@
 
     @Test
     public void testSaveLaunchingStateWhenClearingParent() {
-        LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+        LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
         spyOn(persister);
 
         final Task task = getTestTask();
@@ -915,7 +915,7 @@
 
     @Test
     public void testNotSaveLaunchingStateNonFreeformDisplay() {
-        LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+        LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
         spyOn(persister);
 
         final Task task = getTestTask();
@@ -930,7 +930,7 @@
 
     @Test
     public void testNotSaveLaunchingStateWhenNotFullscreenOrFreeformWindow() {
-        LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
+        LaunchParamsPersister persister = mAtm.mStackSupervisor.mLaunchParamsPersister;
         spyOn(persister);
 
         final Task task = getTestTask();
@@ -983,7 +983,7 @@
     private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
             Rect expectedConfigBounds) {
 
-        TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+        TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
         Task stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -1019,12 +1019,12 @@
             parser.setInput(reader);
             assertEquals(XmlPullParser.START_TAG, parser.next());
             assertEquals(TASK_TAG, parser.getName());
-            return Task.restoreFromXml(parser, mService.mStackSupervisor);
+            return Task.restoreFromXml(parser, mAtm.mStackSupervisor);
         }
     }
 
     private Task createTask(int taskId) {
-        return new Task(mService, taskId, new Intent(), null, null, null,
+        return new Task(mAtm, taskId, new Intent(), null, null, null,
                 ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
                 0, false, null, 0, 0, 0, 0, null, null, 0, false, false, false, 0,
                 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index e8a4e90..75ed928 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -79,6 +79,16 @@
     }
 
     @Test
+    public void testRemoveFinishingInvisibleActivityFromUnknown() {
+        final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent);
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
+        activity.finishing = true;
+        activity.mVisibleRequested = true;
+        activity.setVisibility(false, false);
+        assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
+    }
+
+    @Test
     public void testAppRemoved() {
         final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent);
         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 573e37a..ed9e270 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -295,7 +295,7 @@
     }
 
     private WindowState createWallpaperTargetWindow(DisplayContent dc) {
-        final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+        final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
                 .setStack(dc.getDefaultTaskDisplayArea().getRootHomeTask())
                 .setCreateTask(true)
                 .build();
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 3ebc288..8ac44f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -830,7 +830,7 @@
         final DisplayContent displayContent = createNewDisplay();
         // Do not reparent activity to default display when removing the display.
         doReturn(true).when(displayContent).shouldDestroyContentOnRemove();
-        final ActivityRecord r = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final ActivityRecord r = new StackBuilder(mWm.mRoot)
                 .setDisplay(displayContent).build().getTopMostActivity();
         // Add a window and make the activity animating so the removal of activity is deferred.
         createWindow(null, TYPE_BASE_APPLICATION, r, "win");
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 800a5d4..8cfa4f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -321,7 +321,7 @@
     @Test
     public void testTaskTransaction() {
         removeGlobalMinSizeRestriction();
-        final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final Task stack = new StackBuilder(mWm.mRoot)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         final Task task = stack.getTopMostTask();
         testTransaction(task);
@@ -330,7 +330,7 @@
     @Test
     public void testStackTransaction() {
         removeGlobalMinSizeRestriction();
-        final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final Task stack = new StackBuilder(mWm.mRoot)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         StackInfo info =
                 mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
@@ -355,7 +355,7 @@
 
     @Test
     public void testSetWindowingMode() {
-        final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final Task stack = new StackBuilder(mWm.mRoot)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         testSetWindowingMode(stack);
 
@@ -389,7 +389,7 @@
     @Test
     public void testContainerFocusableChanges() {
         removeGlobalMinSizeRestriction();
-        final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final Task stack = new StackBuilder(mWm.mRoot)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         final Task task = stack.getTopMostTask();
         WindowContainerTransaction t = new WindowContainerTransaction();
@@ -405,7 +405,7 @@
     @Test
     public void testContainerHiddenChanges() {
         removeGlobalMinSizeRestriction();
-        final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final Task stack = new StackBuilder(mWm.mRoot)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         WindowContainerTransaction t = new WindowContainerTransaction();
         assertTrue(stack.shouldBeVisible(null));
@@ -420,7 +420,7 @@
     @Test
     public void testOverrideConfigSize() {
         removeGlobalMinSizeRestriction();
-        final Task stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+        final Task stack = new StackBuilder(mWm.mRoot)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         final Task task = stack.getTopMostTask();
         WindowContainerTransaction t = new WindowContainerTransaction();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java
index cb7bff3..c2ee079 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java
@@ -31,6 +31,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link WindowProcessControllerMap} class.
@@ -40,7 +41,8 @@
  */
 @SmallTest
 @Presubmit
-public class WindowProcessControllerMapTests extends ActivityTestsBase {
+@RunWith(WindowTestRunner.class)
+public class WindowProcessControllerMapTests extends WindowTestsBase {
 
     private static final int FAKE_UID1 = 666;
     private static final int FAKE_UID2 = 667;
@@ -60,23 +62,23 @@
     public void setUp() throws Exception {
         mProcessMap = new WindowProcessControllerMap();
         pid1uid1 = new WindowProcessController(
-                mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid1", FAKE_UID1,
+                mAtm, mAtm.mContext.getApplicationInfo(), "fakepid1fakeuid1", FAKE_UID1,
                 UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
         pid1uid1.setPid(FAKE_PID1);
         pid1uid2 = new WindowProcessController(
-                mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid2", FAKE_UID2,
+                mAtm, mAtm.mContext.getApplicationInfo(), "fakepid1fakeuid2", FAKE_UID2,
                 UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
         pid1uid2.setPid(FAKE_PID1);
         pid2uid1 = new WindowProcessController(
-                mService, mService.mContext.getApplicationInfo(), "fakepid2fakeuid1", FAKE_UID1,
+                mAtm, mAtm.mContext.getApplicationInfo(), "fakepid2fakeuid1", FAKE_UID1,
                 UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
         pid2uid1.setPid(FAKE_PID2);
         pid3uid1 = new WindowProcessController(
-                mService, mService.mContext.getApplicationInfo(), "fakepid3fakeuid1", FAKE_UID1,
+                mAtm, mAtm.mContext.getApplicationInfo(), "fakepid3fakeuid1", FAKE_UID1,
                 UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
         pid3uid1.setPid(FAKE_PID3);
         pid4uid2 = new WindowProcessController(
-                mService, mService.mContext.getApplicationInfo(), "fakepid4fakeuid2", FAKE_UID2,
+                mAtm, mAtm.mContext.getApplicationInfo(), "fakepid4fakeuid2", FAKE_UID2,
                 UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
         pid4uid2.setPid(FAKE_PID4);
     }
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 cdf8eb4..2f73655 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -50,7 +50,7 @@
  */
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class WindowProcessControllerTests extends ActivityTestsBase {
+public class WindowProcessControllerTests extends WindowTestsBase {
 
     WindowProcessController mWpc;
     WindowProcessListener mMockListener;
@@ -62,7 +62,7 @@
         ApplicationInfo info = mock(ApplicationInfo.class);
         info.packageName = "test.package.name";
         mWpc = new WindowProcessController(
-                mService, info, null, 0, -1, null, mMockListener);
+                mAtm, info, null, 0, -1, null, mMockListener);
         mWpc.setThread(mock(IApplicationThread.class));
     }
 
@@ -108,7 +108,7 @@
     public void testSetRunningRecentsAnimation() {
         mWpc.setRunningRecentsAnimation(true);
         mWpc.setRunningRecentsAnimation(false);
-        waitHandlerIdle(mService.mH);
+        waitHandlerIdle(mAtm.mH);
 
         InOrder orderVerifier = Mockito.inOrder(mMockListener);
         orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
@@ -119,7 +119,7 @@
     public void testSetRunningRemoteAnimation() {
         mWpc.setRunningRemoteAnimation(true);
         mWpc.setRunningRemoteAnimation(false);
-        waitHandlerIdle(mService.mH);
+        waitHandlerIdle(mAtm.mH);
 
         InOrder orderVerifier = Mockito.inOrder(mMockListener);
         orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
@@ -133,7 +133,7 @@
 
         mWpc.setRunningRecentsAnimation(false);
         mWpc.setRunningRemoteAnimation(false);
-        waitHandlerIdle(mService.mH);
+        waitHandlerIdle(mAtm.mH);
 
         InOrder orderVerifier = Mockito.inOrder(mMockListener);
         orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true));
@@ -147,12 +147,12 @@
         assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Register to a new display as a listener.
-        final DisplayContent display = new TestDisplayContent.Builder(mService, 2000, 1000)
+        final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2000, 1000)
                 .setDensityDpi(300).setPosition(DisplayContent.POSITION_TOP).build();
         mWpc.registerDisplayConfigurationListener(display);
 
         assertEquals(display.mDisplayId, mWpc.getDisplayId());
-        final Configuration expectedConfig = mService.mRootWindowContainer.getConfiguration();
+        final Configuration expectedConfig = mAtm.mRootWindowContainer.getConfiguration();
         expectedConfig.updateFrom(display.getConfiguration());
         assertEquals(expectedConfig, mWpc.getConfiguration());
     }
@@ -184,15 +184,15 @@
 
     @Test
     public void testActivityNotOverridingSystemUiProcessConfig() {
-        final ComponentName systemUiServiceComponent = mService.getSysUiServiceComponentLocked();
+        final ComponentName systemUiServiceComponent = mAtm.getSysUiServiceComponentLocked();
         ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
         applicationInfo.packageName = systemUiServiceComponent.getPackageName();
 
         WindowProcessController wpc = new WindowProcessController(
-                mService, applicationInfo, null, 0, -1, null, mMockListener);
+                mAtm, applicationInfo, null, 0, -1, null, mMockListener);
         wpc.setThread(mock(IApplicationThread.class));
 
-        final ActivityRecord activity = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setUseProcess(wpc)
                 .build();
@@ -209,7 +209,7 @@
         // Notify WPC that this process has started an IME service.
         mWpc.onServiceStarted(serviceInfo);
 
-        final ActivityRecord activity = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setUseProcess(mWpc)
                 .build();
@@ -226,7 +226,7 @@
         // Notify WPC that this process has started an ally service.
         mWpc.onServiceStarted(serviceInfo);
 
-        final ActivityRecord activity = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setUseProcess(mWpc)
                 .build();
@@ -243,7 +243,7 @@
         // Notify WPC that this process has started an voice interaction service.
         mWpc.onServiceStarted(serviceInfo);
 
-        final ActivityRecord activity = new ActivityBuilder(mService)
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setUseProcess(mWpc)
                 .build();
@@ -254,7 +254,7 @@
     }
 
     private TestDisplayContent createTestDisplayContentInContainer() {
-        return new TestDisplayContent.Builder(mService, 1000, 1500).build();
+        return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
     }
 
     private static void invertOrientation(Configuration config) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 2502932..0180d87 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -25,7 +25,7 @@
 import android.view.IWindow;
 import android.view.WindowManager;
 
-import com.android.server.wm.ActivityTestsBase.ActivityBuilder;
+import com.android.server.wm.WindowTestsBase.ActivityBuilder;
 
 /**
  * A collection of static functions that provide access to WindowManager related test functionality.
@@ -34,7 +34,7 @@
 
     /** Creates a {@link Task} and adds it to the specified {@link Task}. */
     static Task createTaskInStack(WindowManagerService service, Task stack, int userId) {
-        final Task task = new ActivityTestsBase.TaskBuilder(stack.mStackSupervisor)
+        final Task task = new WindowTestsBase.TaskBuilder(stack.mStackSupervisor)
                 .setUserId(userId)
                 .setStack(stack)
                 .build();
@@ -49,7 +49,7 @@
     }
 
     static ActivityRecord createTestActivityRecord(Task stack) {
-        final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+        final ActivityRecord activity = new ActivityBuilder(stack.mAtmService)
                 .setStack(stack)
                 .setCreateTask(true)
                 .build();
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 dc38883..ec19a58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -18,7 +18,13 @@
 
 import static android.app.AppOpsManager.OP_NONE;
 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_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.os.Process.SYSTEM_UID;
 import static android.view.View.VISIBLE;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -37,22 +43,44 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.mock;
 
 import android.annotation.IntDef;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
 import android.hardware.display.DisplayManager;
+import android.os.Build;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.IDisplayWindowInsetsController;
 import android.view.IWindow;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
+import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.WindowManager;
+import android.window.ITaskOrganizer;
+import android.window.WindowContainerToken;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.server.AttributeCache;
@@ -68,11 +96,20 @@
 
 /** Common base class for window manager unit test classes. */
 class WindowTestsBase extends SystemServiceTestsBase {
+    final Context mContext = getInstrumentation().getTargetContext();
 
+    // Default package name
+    static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
+
+    // Default base activity name
+    private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
+
+    ActivityTaskManagerService mAtm;
+    RootWindowContainer mRootWindowContainer;
+    ActivityStackSupervisor mSupervisor;
     WindowManagerService mWm;
     private final IWindow mIWindow = new TestIWindow();
     private Session mMockSession;
-    static int sNextStackId = 1000;
 
     DisplayInfo mDisplayInfo = new DisplayInfo();
     DisplayContent mDefaultDisplay;
@@ -107,6 +144,9 @@
 
     @Before
     public void setUpBase() {
+        mAtm = mSystemServicesTestRule.getActivityTaskManagerService();
+        mSupervisor = mAtm.mStackSupervisor;
+        mRootWindowContainer = mAtm.mRootWindowContainer;
         mWm = mSystemServicesTestRule.getWindowManagerService();
         SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
 
@@ -114,7 +154,7 @@
         mTransaction = mSystemServicesTestRule.mTransaction;
         mMockSession = mock(Session.class);
 
-        getInstrumentation().getTargetContext().getSystemService(DisplayManager.class)
+        mContext.getSystemService(DisplayManager.class)
                 .getDisplay(Display.DEFAULT_DISPLAY).getDisplayInfo(mDisplayInfo);
 
         // Only create an additional test display for annotated test class/method because it may
@@ -328,7 +368,7 @@
     }
 
     Task createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
-        return new ActivityTestsBase.StackBuilder(dc.mWmService.mRoot)
+        return new StackBuilder(dc.mWmService.mRoot)
                 .setDisplay(dc)
                 .setWindowingMode(windowingMode)
                 .setActivityType(activityType)
@@ -339,7 +379,7 @@
 
     Task createTaskStackOnTaskDisplayArea(int windowingMode, int activityType,
             TaskDisplayArea tda) {
-        return new ActivityTestsBase.StackBuilder(tda.mWmService.mRoot)
+        return new StackBuilder(tda.mWmService.mRoot)
                 .setTaskDisplayArea(tda)
                 .setWindowingMode(windowingMode)
                 .setActivityType(activityType)
@@ -371,7 +411,7 @@
     /** Creates a {@link DisplayContent} and adds it to the system. */
     private DisplayContent createNewDisplay(DisplayInfo info, boolean supportIme) {
         final DisplayContent display =
-                new TestDisplayContent.Builder(mWm.mAtmService, info).build();
+                new TestDisplayContent.Builder(mAtm, info).build();
         final DisplayContent dc = display.mDisplayContent;
         // this display can show IME.
         dc.mWmService.mDisplayWindowSettings.setShouldShowImeLocked(dc, supportIme);
@@ -435,11 +475,6 @@
         };
     }
 
-    /** Sets the default minimum task size to 1 so that tests can use small task sizes */
-    void removeGlobalMinSizeRestriction() {
-        mWm.mAtmService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
-    }
-
     /**
      * Avoids rotating screen disturbed by some conditions. It is usually used for the default
      * display that is not the instance of {@link TestDisplayContent} (it bypasses the conditions).
@@ -501,4 +536,523 @@
         boolean addAllCommonWindows() default false;
         @CommonTypes int[] addWindows() default {};
     }
+
+    /** Creates and adds a {@link TestDisplayContent} to supervisor at the given position. */
+    TestDisplayContent addNewDisplayContentAt(int position) {
+        return new TestDisplayContent.Builder(mAtm, 1000, 1500).setPosition(position).build();
+    }
+
+    /** Sets the default minimum task size to 1 so that tests can use small task sizes */
+    public void removeGlobalMinSizeRestriction() {
+        mAtm.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
+    }
+
+    /**
+     * Builder for creating new activities.
+     */
+    protected static class ActivityBuilder {
+        // An id appended to the end of the component name to make it unique
+        private static int sCurrentActivityId = 0;
+
+        private final ActivityTaskManagerService mService;
+
+        private ComponentName mComponent;
+        private String mTargetActivity;
+        private Task mTask;
+        private String mProcessName = "name";
+        private String mAffinity;
+        private int mUid = 12345;
+        private boolean mCreateTask;
+        private Task mStack;
+        private int mActivityFlags;
+        private int mLaunchMode;
+        private int mResizeMode = RESIZE_MODE_RESIZEABLE;
+        private float mMaxAspectRatio;
+        private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+        private boolean mLaunchTaskBehind;
+        private int mConfigChanges;
+        private int mLaunchedFromPid;
+        private int mLaunchedFromUid;
+        private WindowProcessController mWpc;
+        private Bundle mIntentExtras;
+
+        ActivityBuilder(ActivityTaskManagerService service) {
+            mService = service;
+        }
+
+        ActivityBuilder setComponent(ComponentName component) {
+            mComponent = component;
+            return this;
+        }
+
+        ActivityBuilder setTargetActivity(String targetActivity) {
+            mTargetActivity = targetActivity;
+            return this;
+        }
+
+        ActivityBuilder setIntentExtras(Bundle extras) {
+            mIntentExtras = extras;
+            return this;
+        }
+
+        static ComponentName getDefaultComponent() {
+            return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+                    DEFAULT_COMPONENT_PACKAGE_NAME);
+        }
+
+        ActivityBuilder setTask(Task task) {
+            mTask = task;
+            return this;
+        }
+
+        ActivityBuilder setActivityFlags(int flags) {
+            mActivityFlags = flags;
+            return this;
+        }
+
+        ActivityBuilder setLaunchMode(int launchMode) {
+            mLaunchMode = launchMode;
+            return this;
+        }
+
+        ActivityBuilder setStack(Task stack) {
+            mStack = stack;
+            return this;
+        }
+
+        ActivityBuilder setCreateTask(boolean createTask) {
+            mCreateTask = createTask;
+            return this;
+        }
+
+        ActivityBuilder setProcessName(String name) {
+            mProcessName = name;
+            return this;
+        }
+
+        ActivityBuilder setUid(int uid) {
+            mUid = uid;
+            return this;
+        }
+
+        ActivityBuilder setResizeMode(int resizeMode) {
+            mResizeMode = resizeMode;
+            return this;
+        }
+
+        ActivityBuilder setMaxAspectRatio(float maxAspectRatio) {
+            mMaxAspectRatio = maxAspectRatio;
+            return this;
+        }
+
+        ActivityBuilder setScreenOrientation(int screenOrientation) {
+            mScreenOrientation = screenOrientation;
+            return this;
+        }
+
+        ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) {
+            mLaunchTaskBehind = launchTaskBehind;
+            return this;
+        }
+
+        ActivityBuilder setConfigChanges(int configChanges) {
+            mConfigChanges = configChanges;
+            return this;
+        }
+
+        ActivityBuilder setLaunchedFromPid(int pid) {
+            mLaunchedFromPid = pid;
+            return this;
+        }
+
+        ActivityBuilder setLaunchedFromUid(int uid) {
+            mLaunchedFromUid = uid;
+            return this;
+        }
+
+        ActivityBuilder setUseProcess(WindowProcessController wpc) {
+            mWpc = wpc;
+            return this;
+        }
+
+        ActivityBuilder setAffinity(String affinity) {
+            mAffinity = affinity;
+            return this;
+        }
+
+        ActivityRecord build() {
+            SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
+            try {
+                mService.deferWindowLayout();
+                return buildInner();
+            } finally {
+                mService.continueWindowLayout();
+            }
+        }
+
+        ActivityRecord buildInner() {
+            if (mComponent == null) {
+                final int id = sCurrentActivityId++;
+                mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+                        DEFAULT_COMPONENT_CLASS_NAME + id);
+            }
+
+            if (mCreateTask) {
+                mTask = new TaskBuilder(mService.mStackSupervisor)
+                        .setComponent(mComponent)
+                        .setStack(mStack).build();
+            } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
+                    mStack.getWindowingMode(), mStack.getActivityType())) {
+                // The stack can be the task root.
+                mTask = mStack;
+            }
+
+            Intent intent = new Intent();
+            intent.setComponent(mComponent);
+            if (mIntentExtras != null) {
+                intent.putExtras(mIntentExtras);
+            }
+            final ActivityInfo aInfo = new ActivityInfo();
+            aInfo.applicationInfo = new ApplicationInfo();
+            aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+            aInfo.applicationInfo.packageName = mComponent.getPackageName();
+            aInfo.applicationInfo.uid = mUid;
+            aInfo.processName = mProcessName;
+            aInfo.packageName = mComponent.getPackageName();
+            aInfo.name = mComponent.getClassName();
+            if (mTargetActivity != null) {
+                aInfo.targetActivity = mTargetActivity;
+            }
+            aInfo.flags |= mActivityFlags;
+            aInfo.launchMode = mLaunchMode;
+            aInfo.resizeMode = mResizeMode;
+            aInfo.maxAspectRatio = mMaxAspectRatio;
+            aInfo.screenOrientation = mScreenOrientation;
+            aInfo.configChanges |= mConfigChanges;
+            aInfo.taskAffinity = mAffinity;
+
+            ActivityOptions options = null;
+            if (mLaunchTaskBehind) {
+                options = ActivityOptions.makeTaskLaunchBehind();
+            }
+
+            final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
+                    mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
+                    null, null, intent, null, aInfo /*aInfo*/, new Configuration(),
+                    null /* resultTo */, null /* resultWho */, 0 /* reqCode */,
+                    false /*componentSpecified*/, false /* rootVoiceInteraction */,
+                    mService.mStackSupervisor, options, null /* sourceRecord */);
+            spyOn(activity);
+            if (mTask != null) {
+                // fullscreen value is normally read from resources in ctor, so for testing we need
+                // to set it somewhere else since we can't mock resources.
+                doReturn(true).when(activity).occludesParent();
+                doReturn(true).when(activity).fillsParent();
+                mTask.addChild(activity);
+                // Make visible by default...
+                activity.setVisible(true);
+            }
+
+            final WindowProcessController wpc;
+            if (mWpc != null) {
+                wpc = mWpc;
+            } else {
+                wpc = new WindowProcessController(mService,
+                        aInfo.applicationInfo, mProcessName, mUid,
+                        UserHandle.getUserId(12345), mock(Object.class),
+                        mock(WindowProcessListener.class));
+                wpc.setThread(mock(IApplicationThread.class));
+            }
+            wpc.setThread(mock(IApplicationThread.class));
+            activity.setProcess(wpc);
+            doReturn(wpc).when(mService).getProcessController(
+                    activity.processName, activity.info.applicationInfo.uid);
+
+            // Resume top activities to make sure all other signals in the system are connected.
+            mService.mRootWindowContainer.resumeFocusedStacksTopActivities();
+            return activity;
+        }
+    }
+
+    /**
+     * Builder for creating new tasks.
+     */
+    protected static class TaskBuilder {
+        private final ActivityStackSupervisor mSupervisor;
+
+        private ComponentName mComponent;
+        private String mPackage;
+        private int mFlags = 0;
+        // Task id 0 is reserved in ARC for the home app.
+        private int mTaskId = SystemServicesTestRule.sNextTaskId++;
+        private int mUserId = 0;
+        private IVoiceInteractionSession mVoiceSession;
+        private boolean mCreateStack = true;
+
+        private Task mStack;
+        private TaskDisplayArea mTaskDisplayArea;
+
+        TaskBuilder(ActivityStackSupervisor supervisor) {
+            mSupervisor = supervisor;
+        }
+
+        TaskBuilder setComponent(ComponentName component) {
+            mComponent = component;
+            return this;
+        }
+
+        TaskBuilder setPackage(String packageName) {
+            mPackage = packageName;
+            return this;
+        }
+
+        /**
+         * Set to {@code true} by default, set to {@code false} to prevent the task from
+         * automatically creating a parent stack.
+         */
+        TaskBuilder setCreateStack(boolean createStack) {
+            mCreateStack = createStack;
+            return this;
+        }
+
+        TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
+            mVoiceSession = session;
+            return this;
+        }
+
+        TaskBuilder setFlags(int flags) {
+            mFlags = flags;
+            return this;
+        }
+
+        TaskBuilder setTaskId(int taskId) {
+            mTaskId = taskId;
+            return this;
+        }
+
+        TaskBuilder setUserId(int userId) {
+            mUserId = userId;
+            return this;
+        }
+
+        TaskBuilder setStack(Task stack) {
+            mStack = stack;
+            return this;
+        }
+
+        TaskBuilder setDisplay(DisplayContent display) {
+            mTaskDisplayArea = display.getDefaultTaskDisplayArea();
+            return this;
+        }
+
+        Task build() {
+            SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
+
+            if (mStack == null && mCreateStack) {
+                TaskDisplayArea displayArea = mTaskDisplayArea != null ? mTaskDisplayArea
+                        : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+                mStack = displayArea.createStack(
+                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+                spyOn(mStack);
+            }
+
+            final ActivityInfo aInfo = new ActivityInfo();
+            aInfo.applicationInfo = new ApplicationInfo();
+            aInfo.applicationInfo.packageName = mPackage;
+
+            Intent intent = new Intent();
+            if (mComponent == null) {
+                mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+                        DEFAULT_COMPONENT_CLASS_NAME);
+            }
+
+            intent.setComponent(mComponent);
+            intent.setFlags(mFlags);
+
+            final Task task = new Task(mSupervisor.mService, mTaskId, aInfo,
+                    intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
+                    null /*taskDescription*/, mStack);
+            spyOn(task);
+            task.mUserId = mUserId;
+
+            if (mStack != null) {
+                mStack.moveToFront("test");
+                mStack.addChild(task, true, true);
+            }
+
+            return task;
+        }
+    }
+
+    static class StackBuilder {
+        private final RootWindowContainer mRootWindowContainer;
+        private DisplayContent mDisplay;
+        private TaskDisplayArea mTaskDisplayArea;
+        private int mStackId = -1;
+        private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+        private int mActivityType = ACTIVITY_TYPE_STANDARD;
+        private boolean mOnTop = true;
+        private boolean mCreateActivity = true;
+        private ActivityInfo mInfo;
+        private Intent mIntent;
+
+        StackBuilder(RootWindowContainer root) {
+            mRootWindowContainer = root;
+            mDisplay = mRootWindowContainer.getDefaultDisplay();
+            mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
+        }
+
+        StackBuilder setWindowingMode(int windowingMode) {
+            mWindowingMode = windowingMode;
+            return this;
+        }
+
+        StackBuilder setActivityType(int activityType) {
+            mActivityType = activityType;
+            return this;
+        }
+
+        StackBuilder setStackId(int stackId) {
+            mStackId = stackId;
+            return this;
+        }
+
+        /**
+         * Set the parent {@link DisplayContent} and use the default task display area. Overrides
+         * the task display area, if was set before.
+         */
+        StackBuilder setDisplay(DisplayContent display) {
+            mDisplay = display;
+            mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
+            return this;
+        }
+
+        /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */
+        StackBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
+            mTaskDisplayArea = taskDisplayArea;
+            mDisplay = mTaskDisplayArea.mDisplayContent;
+            return this;
+        }
+
+        StackBuilder setOnTop(boolean onTop) {
+            mOnTop = onTop;
+            return this;
+        }
+
+        StackBuilder setCreateActivity(boolean createActivity) {
+            mCreateActivity = createActivity;
+            return this;
+        }
+
+        StackBuilder setActivityInfo(ActivityInfo info) {
+            mInfo = info;
+            return this;
+        }
+
+        StackBuilder setIntent(Intent intent) {
+            mIntent = intent;
+            return this;
+        }
+
+        Task build() {
+            SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock);
+
+            final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId();
+            final Task stack = mTaskDisplayArea.createStackUnchecked(
+                    mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
+                    false /* createdByOrganizer */);
+            final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
+
+            if (mCreateActivity) {
+                new ActivityBuilder(supervisor.mService)
+                        .setCreateTask(true)
+                        .setStack(stack)
+                        .build();
+                if (mOnTop) {
+                    // We move the task to front again in order to regain focus after activity
+                    // added to the stack. Or {@link DisplayContent#mPreferredTopFocusableStack}
+                    // could be other stacks (e.g. home stack).
+                    stack.moveToFront("createActivityStack");
+                } else {
+                    stack.moveToBack("createActivityStack", null);
+                }
+            }
+            spyOn(stack);
+
+            doNothing().when(stack).startActivityLocked(
+                    any(), any(), anyBoolean(), anyBoolean(), any());
+
+            return stack;
+        }
+
+    }
+
+    static class TestSplitOrganizer extends ITaskOrganizer.Stub {
+        final ActivityTaskManagerService mService;
+        Task mPrimary;
+        Task mSecondary;
+        boolean mInSplit = false;
+        // moves everything to secondary. Most tests expect this since sysui usually does it.
+        boolean mMoveToSecondaryOnEnter = true;
+        int mDisplayId;
+        TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
+            mService = service;
+            mDisplayId = displayId;
+            mService.mTaskOrganizerController.registerTaskOrganizer(this,
+                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+            mService.mTaskOrganizerController.registerTaskOrganizer(this,
+                    WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+            WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
+                    displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
+            mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
+            WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
+                    displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
+            mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
+        }
+        TestSplitOrganizer(ActivityTaskManagerService service) {
+            this(service,
+                    service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId);
+        }
+        public void setMoveToSecondaryOnEnter(boolean move) {
+            mMoveToSecondaryOnEnter = move;
+        }
+        @Override
+        public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
+        }
+        @Override
+        public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
+        }
+        @Override
+        public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+            if (mInSplit) {
+                return;
+            }
+            if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) {
+                // Not populated
+                return;
+            }
+            if (info.configuration.windowConfiguration.getWindowingMode()
+                    != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                return;
+            }
+            mInSplit = true;
+            if (!mMoveToSecondaryOnEnter) {
+                return;
+            }
+            mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
+                    mSecondary.mRemoteToken.toWindowContainerToken());
+            DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
+            dc.forAllTaskDisplayAreas(taskDisplayArea -> {
+                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+                    final Task stack = taskDisplayArea.getStackAt(sNdx);
+                    if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
+                        stack.reparent(mSecondary, POSITION_BOTTOM);
+                    }
+                }
+            });
+        }
+        @Override
+        public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+        }
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 6861ad1..4986d18 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -307,7 +307,7 @@
                 }
             } else {
                 if (mActives > mObserved.length) {
-                    // Try to get to a sane state and log the issue
+                    // Try to get to a valid state and log the issue
                     mActives = mObserved.length;
                     final UserData user = mUserRef.get();
                     if (user == null) return;
@@ -334,7 +334,7 @@
                 cancelCheckTimeoutLocked(this);
             } else {
                 if (mActives < 0) {
-                    // Try to get to a sane state and log the issue
+                    // Try to get to a valid state and log the issue
                     mActives = 0;
                     final UserData user = mUserRef.get();
                     if (user == null) return;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 9b18ec6..2fd6c42 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -92,6 +92,7 @@
 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;
@@ -291,27 +292,26 @@
     }
 
     @Override
-    public void onStartUser(UserInfo userInfo) {
+    public void onUserStarting(@NonNull TargetUser user) {
         // Create an entry in the user state map to indicate that the user has been started but
         // not necessarily unlocked. This will ensure that reported events are flushed to disk
         // event if the user is never unlocked (following the logic in #flushToDiskLocked)
-        mUserState.put(userInfo.id, null);
-        super.onStartUser(userInfo);
+        mUserState.put(user.getUserIdentifier(), null);
     }
 
     @Override
-    public void onUnlockUser(@NonNull UserInfo userInfo) {
-        mHandler.obtainMessage(MSG_UNLOCKED_USER, userInfo.id, 0).sendToTarget();
-        super.onUnlockUser(userInfo);
+    public void onUserUnlocking(@NonNull TargetUser user) {
+        mHandler.obtainMessage(MSG_UNLOCKED_USER, user.getUserIdentifier(), 0).sendToTarget();
     }
 
     @Override
-    public void onStopUser(@NonNull UserInfo userInfo) {
+    public void onUserStopping(@NonNull TargetUser user) {
+        final UserInfo userInfo = user.getUserInfo();
+
         synchronized (mLock) {
             // User was started but never unlocked so no need to report a user stopped event
             if (!mUserUnlockedStates.get(userInfo.id)) {
                 persistPendingEventsLocked(userInfo.id);
-                super.onStopUser(userInfo);
                 return;
             }
 
@@ -326,7 +326,6 @@
             mUserUnlockedStates.put(userInfo.id, false);
             mUserState.put(userInfo.id, null); // release the service (mainly for GC)
         }
-        super.onStopUser(userInfo);
     }
 
     private void onUserUnlocked(int userId) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 534fe03..0ea84da 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -221,14 +221,6 @@
         }
     }
 
-    @Override
-    public void onStartUser(int userHandle) {
-    }
-
-    @Override
-    public void onSwitchUser(int userHandle) {
-    }
-
     private synchronized void initSoundTriggerHelper() {
         if (mSoundTriggerHelper == null) {
             mSoundTriggerHelper = new SoundTriggerHelper(mContext);
@@ -1289,27 +1281,25 @@
             attributesBuilder.setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD);
             AudioAttributes attributes = attributesBuilder.build();
 
-            // Use same AudioFormat processing as in RecognitionEvent.fromParcel
             AudioFormat originalFormat = event.getCaptureFormat();
-            AudioFormat captureFormat = (new AudioFormat.Builder())
-                    .setChannelMask(originalFormat.getChannelMask())
-                    .setEncoding(originalFormat.getEncoding())
-                    .setSampleRate(originalFormat.getSampleRate())
-                    .build();
-
-            int bufferSize = AudioRecord.getMinBufferSize(
-                    captureFormat.getSampleRate() == AudioFormat.SAMPLE_RATE_UNSPECIFIED
-                            ? AudioFormat.SAMPLE_RATE_HZ_MAX
-                            : captureFormat.getSampleRate(),
-                    captureFormat.getChannelCount() == 2
-                            ? AudioFormat.CHANNEL_IN_STEREO
-                            : AudioFormat.CHANNEL_IN_MONO,
-                    captureFormat.getEncoding());
 
             sEventLogger.log(new SoundTriggerLogger.StringEvent("createAudioRecordForEvent"));
 
-            return new AudioRecord(attributes, captureFormat, bufferSize,
-                    event.getCaptureSession());
+            try {
+                return (new AudioRecord.Builder())
+                            .setAudioAttributes(attributes)
+                            .setAudioFormat((new AudioFormat.Builder())
+                                .setChannelMask(originalFormat.getChannelMask())
+                                .setEncoding(originalFormat.getEncoding())
+                                .setSampleRate(originalFormat.getSampleRate())
+                                .build())
+                            .setSessionId(event.getCaptureSession())
+                            .build();
+            } catch (IllegalArgumentException | UnsupportedOperationException e) {
+                Slog.w(TAG, mPuuid + ": createAudioRecordForEvent(" + event
+                        + "), failed to create AudioRecord");
+                return null;
+            }
         }
 
         @Override
@@ -1339,8 +1329,10 @@
 
                             // Currently we need to start and release the audio record to reset
                             // the DSP even if we don't want to process the event
-                            capturedData.startRecording();
-                            capturedData.release();
+                            if (capturedData != null) {
+                                capturedData.startRecording();
+                                capturedData.release();
+                            }
                         }
                     }));
         }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 9621f68..0f898f8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -189,10 +189,10 @@
     }
 
     @Override
-    public void onSwitchUser(@NonNull UserInfo from, @NonNull UserInfo to) {
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         if (DEBUG_USER) Slog.d(TAG, "onSwitchUser(" + from + " > " + to + ")");
 
-        mServiceStub.switchUser(to.id);
+        mServiceStub.switchUser(to.getUserIdentifier());
     }
 
     class LocalService extends VoiceInteractionManagerInternal {
diff --git a/startop/OWNERS b/startop/OWNERS
index 3394be9..2d1eb38 100644
--- a/startop/OWNERS
+++ b/startop/OWNERS
@@ -1,7 +1,7 @@
 # mailing list: startop-eng@google.com
+calin@google.com
 chriswailes@google.com
 eholk@google.com
 iam@google.com
 mathieuc@google.com
-sehr@google.com
 yawanng@google.com
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index ef94c76..09c1659 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -316,6 +316,7 @@
     method @Deprecated public int getDataConnectionApnTypeBitMask();
     method @Deprecated public int getDataConnectionFailCause();
     method @Deprecated public int getDataConnectionState();
+    method public int getId();
   }
 
   public final class PreciseDisconnectCause {
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index aee8617..fd9f460 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -28,11 +28,15 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.DataState;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.data.ApnSetting;
+import android.telephony.data.DataCallResponse;
+
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.util.Objects;
 
@@ -53,6 +57,8 @@
  *
  */
 public final class PreciseDataConnectionState implements Parcelable {
+    private final @TransportType int mTransportType;
+    private final int mId;
     private final @DataState int mState;
     private final @NetworkType int mNetworkType;
     private final @DataFailureCause int mFailCause;
@@ -74,16 +80,20 @@
                                       @ApnType int apnTypes, @NonNull String apn,
                                       @Nullable LinkProperties linkProperties,
                                       @DataFailureCause int failCause) {
-        this(state, networkType, linkProperties, failCause, new ApnSetting.Builder()
-                .setApnTypeBitmask(apnTypes)
-                .setApnName(apn)
-                .build());
+        this(AccessNetworkConstants.TRANSPORT_TYPE_INVALID, -1, state, networkType,
+                linkProperties, failCause, new ApnSetting.Builder()
+                        .setApnTypeBitmask(apnTypes)
+                        .setApnName(apn)
+                        .setEntryName(apn)
+                        .build());
     }
 
 
     /**
      * Constructor of PreciseDataConnectionState
      *
+     * @param transportType The transport of the data connection
+     * @param id The id of the data connection
      * @param state The state of the data connection
      * @param networkType The access network that is/would carry this data connection
      * @param linkProperties If the data connection is connected, the properties of the connection
@@ -92,11 +102,12 @@
      * @param apnSetting If there is a valid APN for this Data Connection, then the APN Settings;
      *        if there is no valid APN setting for the specific type, then this will be null
      */
-    private PreciseDataConnectionState(@DataState int state,
-                                      @NetworkType int networkType,
-                                      @Nullable LinkProperties linkProperties,
-                                      @DataFailureCause int failCause,
-                                      @Nullable ApnSetting apnSetting) {
+    private PreciseDataConnectionState(@TransportType int transportType, int id,
+            @DataState int state, @NetworkType int networkType,
+            @Nullable LinkProperties linkProperties, @DataFailureCause int failCause,
+            @Nullable ApnSetting apnSetting) {
+        mTransportType = transportType;
+        mId = id;
         mState = state;
         mNetworkType = networkType;
         mLinkProperties = linkProperties;
@@ -110,6 +121,8 @@
      * @hide
      */
     private PreciseDataConnectionState(Parcel in) {
+        mTransportType = in.readInt();
+        mId = in.readInt();
         mState = in.readInt();
         mNetworkType = in.readInt();
         mLinkProperties = in.readParcelable(LinkProperties.class.getClassLoader());
@@ -144,7 +157,29 @@
     }
 
     /**
-     * Returns the high-level state of this data connection.
+     * @return The transport type of this data connection.
+     */
+    public @TransportType int getTransportType() {
+        return mTransportType;
+    }
+
+    /**
+     * @return The unique id of the data connection
+     *
+     * Note this is the id assigned in {@link DataCallResponse}.
+     * The id remains the same for data connection handover between
+     * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN} and
+     * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * @return The high-level state of this data connection.
      */
     public @DataState int getState() {
         return mState;
@@ -222,7 +257,9 @@
     /**
      * Return the APN Settings for this data connection.
      *
-     * @return the ApnSetting that was used to configure this data connection.
+     * @return the ApnSetting that was used to configure this data connection. Note that a data
+     * connection cannot be established without a valid {@link ApnSetting}. The return value would
+     * never be {@code null} even though it has {@link Nullable} annotation.
      */
     public @Nullable ApnSetting getApnSetting() {
         return mApnSetting;
@@ -235,6 +272,8 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mTransportType);
+        out.writeInt(mId);
         out.writeInt(mState);
         out.writeInt(mNetworkType);
         out.writeParcelable(mLinkProperties, flags);
@@ -256,7 +295,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mState, mNetworkType, mFailCause, mLinkProperties, mApnSetting);
+        return Objects.hash(mTransportType, mId, mState, mNetworkType, mFailCause,
+                mLinkProperties, mApnSetting);
     }
 
 
@@ -265,7 +305,9 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         PreciseDataConnectionState that = (PreciseDataConnectionState) o;
-        return mState == that.mState
+        return mTransportType == that.mTransportType
+                && mId == that.mId
+                && mState == that.mState
                 && mNetworkType == that.mNetworkType
                 && mFailCause == that.mFailCause
                 && Objects.equals(mLinkProperties, that.mLinkProperties)
@@ -277,14 +319,14 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
 
-        sb.append("Data Connection state: " + mState);
-        sb.append(", Network type: " + mNetworkType);
-        sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(
-                getDataConnectionApnTypeBitMask()));
-        sb.append(", APN: " + getDataConnectionApn());
-        sb.append(", Link properties: " + mLinkProperties);
-        sb.append(", Fail cause: " + DataFailCause.toString(mFailCause));
-        sb.append(", Apn Setting: " + mApnSetting);
+        sb.append(" state: " + TelephonyUtils.dataStateToString(mState));
+        sb.append(", transport: "
+                + AccessNetworkConstants.transportTypeToString(mTransportType));
+        sb.append(", id: " + mId);
+        sb.append(", network type: " + TelephonyManager.getNetworkTypeName(mNetworkType));
+        sb.append(", APN Setting: " + mApnSetting);
+        sb.append(", link properties: " + mLinkProperties);
+        sb.append(", fail cause: " + DataFailCause.toString(mFailCause));
 
         return sb.toString();
     }
@@ -295,6 +337,15 @@
      * @hide
      */
     public static final class Builder {
+        /** The transport type of the data connection */
+        private @TransportType int mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+
+        /**
+         * The unique ID of the data connection. This is the id assigned in
+         * {@link DataCallResponse)}.
+         */
+        private int mId = -1;
+
         /** The state of the data connection */
         private @DataState int mState = TelephonyManager.DATA_UNKNOWN;
 
@@ -314,12 +365,34 @@
         private @Nullable ApnSetting mApnSetting = null;
 
         /**
+         * Set the transport type of the data connection.
+         *
+         * @param transportType The transport type of the data connection
+         * @return The builder
+         */
+        public @NonNull Builder setTransportType(@TransportType int transportType) {
+            mTransportType = transportType;
+            return this;
+        }
+
+        /**
+         * Set the id of the data connection.
+         *
+         * @param id The id of the data connection
+         * @return The builder
+         */
+        public @NonNull Builder setId(int id) {
+            mId = id;
+            return this;
+        }
+
+        /**
          * Set the state of the data connection.
          *
          * @param state The state of the data connection
          * @return The builder
          */
-        public Builder setState(@DataState int state) {
+        public @NonNull Builder setState(@DataState int state) {
             mState = state;
             return this;
         }
@@ -330,7 +403,7 @@
          * @param networkType The network type
          * @return The builder
          */
-        public Builder setNetworkType(@NetworkType int networkType) {
+        public @NonNull Builder setNetworkType(@NetworkType int networkType) {
             mNetworkType = networkType;
             return this;
         }
@@ -341,7 +414,7 @@
          * @param linkProperties Link properties
          * @return The builder
          */
-        public Builder setLinkProperties(@NonNull LinkProperties linkProperties) {
+        public @NonNull Builder setLinkProperties(LinkProperties linkProperties) {
             mLinkProperties = linkProperties;
             return this;
         }
@@ -353,7 +426,7 @@
          * error code indicating the cause of the failure.
          * @return The builder
          */
-        public Builder setFailCause(@DataFailureCause int failCause) {
+        public @NonNull Builder setFailCause(@DataFailureCause int failCause) {
             mFailCause = failCause;
             return this;
         }
@@ -364,7 +437,7 @@
          * @param apnSetting APN setting
          * @return This builder
          */
-        public Builder setApnSetting(@NonNull ApnSetting apnSetting) {
+        public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) {
             mApnSetting = apnSetting;
             return this;
         }
@@ -375,8 +448,8 @@
          * @return The {@link PreciseDataConnectionState} instance
          */
         public PreciseDataConnectionState build() {
-            return new PreciseDataConnectionState(mState, mNetworkType, mLinkProperties, mFailCause,
-                    mApnSetting);
+            return new PreciseDataConnectionState(mTransportType, mId, mState, mNetworkType,
+                    mLinkProperties, mFailCause, mApnSetting);
         }
     }
 }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index e60ae89..ff9329ef 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1214,12 +1214,16 @@
         return false;
     }
 
-    // TODO - if we have this function we should also have hashCode.
-    // Also should handle changes in type order and perhaps case-insensitivity.
+    @Override
+    public int hashCode() {
+        return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress,
+                mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric,
+                mProtocol, mRoamingProtocol, mMtu, mCarrierEnabled, mNetworkTypeBitmask, mProfileId,
+                mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData,
+                mApnSetId, mCarrierId, mSkip464Xlat);
+    }
 
-    /**
-     * @hide
-     */
+    @Override
     public boolean equals(Object o) {
         if (o instanceof ApnSetting == false) {
             return false;
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index f898516..b2fdc50 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -125,7 +125,7 @@
         } catch (IllegalArgumentException e) {
             runFailed("Illegal argument passed to constructor. Class: " + testClass.getName());
         } catch (InvocationTargetException e) {
-            runFailed("Constructor thew an exception. Class: " + testClass.getName());
+            runFailed("Constructor threw an exception. Class: " + testClass.getName());
         }
         return null;
     }
diff --git a/tests/BootImageProfileTest/OWNERS b/tests/BootImageProfileTest/OWNERS
index 657b3f2..7ee0d9a 100644
--- a/tests/BootImageProfileTest/OWNERS
+++ b/tests/BootImageProfileTest/OWNERS
@@ -1,4 +1,4 @@
-mathieuc@google.com
 calin@google.com
+mathieuc@google.com
+ngeoffray@google.com
 yawanng@google.com
-sehr@google.com
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index dcabce8..c1a3ed69 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker
 
+import com.android.server.wm.flicker.dsl.EventLogAssertion
 import com.android.server.wm.flicker.dsl.LayersAssertion
 import com.android.server.wm.flicker.dsl.WmAssertion
 import com.android.server.wm.flicker.helpers.WindowUtils
@@ -53,19 +54,19 @@
     if (allStates) {
         all("noUncoveredRegions", enabled, bugId) {
             if (startingBounds == endingBounds) {
-                this.coversRegion(startingBounds)
+                this.coversAtLeastRegion(startingBounds)
             } else {
-                this.coversRegion(startingBounds)
+                this.coversAtLeastRegion(startingBounds)
                         .then()
-                        .coversRegion(endingBounds)
+                        .coversAtLeastRegion(endingBounds)
             }
         }
     } else {
         start("noUncoveredRegions_StartingPos") {
-            this.coversRegion(startingBounds)
+            this.coversAtLeastRegion(startingBounds)
         }
         end("noUncoveredRegions_EndingPos") {
-            this.coversRegion(endingBounds)
+            this.coversAtLeastRegion(endingBounds)
         }
     }
 }
@@ -130,4 +131,23 @@
     end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
         this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
     }
+}
+
+fun EventLogAssertion.focusChanges(
+    vararg windows: String,
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all(enabled = enabled, bugId = bugId) {
+        this.focusChanges(windows)
+    }
+}
+
+fun EventLogAssertion.focusDoesNotChange(
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all(enabled = enabled, bugId = bugId) {
+        this.focusDoesNotChange()
+    }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
index eaf4d87..abe7dbc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
@@ -92,7 +92,7 @@
         app2: IAppHelper?,
         extraInfo: String
     ): String {
-        var testTag = "${testName}__$${app.launcherName}"
+        var testTag = "${testName}__${app.launcherName}"
         if (app2 != null) {
             testTag += "-${app2.launcherName}"
         }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 31d1fd3..2e4d390 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -81,11 +81,11 @@
                 }
 
                 layersTrace {
-                    navBarLayerIsAlwaysVisible()
-                    statusBarLayerIsAlwaysVisible()
-                    noUncoveredRegions(rotation)
-                    navBarLayerRotatesAndScales(rotation)
-                    statusBarLayerRotatesScales(rotation)
+                    navBarLayerIsAlwaysVisible(bugId = 140855415)
+                    statusBarLayerIsAlwaysVisible(bugId = 140855415)
+                    noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
+                    navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+                    statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
                     imeLayerBecomesInvisible(bugId = 141458352)
                     imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
                 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index b643ec2..1c0da4f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -89,9 +89,9 @@
                 }
 
                 layersTrace {
-                    navBarLayerIsAlwaysVisible()
-                    statusBarLayerIsAlwaysVisible()
-                    noUncoveredRegions(rotation)
+                    navBarLayerIsAlwaysVisible(bugId = 140855415)
+                    statusBarLayerIsAlwaysVisible(bugId = 140855415)
+                    noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
                     navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
                     statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
                     imeLayerBecomesInvisible(bugId = 153739621)
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 1240e0d..62337e9 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
@@ -19,6 +19,7 @@
 import android.view.Surface
 import androidx.test.filters.LargeTest
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -70,18 +71,22 @@
                 windowManagerTrace {
                     navBarWindowIsAlwaysVisible()
                     statusBarWindowIsAlwaysVisible()
-                    appWindowReplacesLauncherAsTopWindow(bugId = 141361128)
+                    appWindowReplacesLauncherAsTopWindow()
                     wallpaperWindowBecomesInvisible()
                 }
 
                 layersTrace {
-                    noUncoveredRegions(rotation, bugId = 141361128)
                     // During testing the launcher is always in portrait mode
+                    noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128)
                     navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
                     statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
-                    navBarLayerIsAlwaysVisible(bugId = 141361128)
-                    statusBarLayerIsAlwaysVisible(bugId = 141361128)
-                    wallpaperLayerBecomesInvisible(bugId = 141361128)
+                    navBarLayerIsAlwaysVisible()
+                    statusBarLayerIsAlwaysVisible(enabled = false)
+                    wallpaperLayerBecomesInvisible()
+                }
+
+                eventLog {
+                    focusChanges("NexusLauncherActivity", testApp.`package`)
                 }
             }
         }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
index 3cec077..7d70812 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
@@ -44,10 +44,9 @@
         enabled: Boolean = bugId == 0
     ) {
         all("appWindowReplacesLauncherAsTopWindow", enabled, bugId) {
-            this.showsAppWindowOnTop(
-                    "Launcher")
+            this.showsAppWindowOnTop("Launcher")
                     .then()
-                    .showsAppWindowOnTop(testApp.getPackage())
+                    .showsAppWindowOnTop("Snapshot", testApp.getPackage())
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 98413a1..9a8e37b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.LargeTest
 import com.android.server.wm.flicker.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -78,18 +79,22 @@
                 windowManagerTrace {
                     navBarWindowIsAlwaysVisible()
                     statusBarWindowIsAlwaysVisible()
-                    appWindowReplacesLauncherAsTopWindow(bugId = 141361128)
+                    appWindowReplacesLauncherAsTopWindow()
                     wallpaperWindowBecomesInvisible(enabled = false)
                 }
 
                 layersTrace {
-                    noUncoveredRegions(rotation, bugId = 141361128)
                     // During testing the launcher is always in portrait mode
+                    noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128)
                     navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
                     statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
-                    navBarLayerIsAlwaysVisible(bugId = 141361128)
-                    statusBarLayerIsAlwaysVisible(bugId = 141361128)
-                    wallpaperLayerBecomesInvisible(bugId = 141361128)
+                    navBarLayerIsAlwaysVisible()
+                    statusBarLayerIsAlwaysVisible(enabled = false)
+                    wallpaperLayerBecomesInvisible()
+                }
+
+                eventLog {
+                    focusChanges("NexusLauncherActivity", testApp.`package`)
                 }
             }
         }
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
new file mode 100644
index 0000000..4acd975
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
@@ -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.server.wm.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.dsl.flicker
+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.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.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+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 FlickerTests:PipToAppTest`
+ */
+@LargeTest
+@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)
+                device.expandPipWindow()
+            }
+            assertions {
+                windowManagerTrace {
+                    navBarWindowIsAlwaysVisible()
+                    statusBarWindowIsAlwaysVisible()
+                    all("pipWindowBecomesVisible") {
+                        this.showsAppWindow(testApp.`package`)
+                                .then()
+                                .showsAppWindow(sPipWindowTitle)
+                    }
+                }
+
+                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(sPipWindowTitle)
+                    }
+                }
+            }
+        }
+    }
+
+    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/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
index 4afabd4..691db7fb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
@@ -16,9 +16,7 @@
 
 package com.android.server.wm.flicker.pip
 
-import com.android.server.wm.flicker.dsl.LayersAssertion
 import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.dsl.WmAssertion
 import com.android.server.wm.flicker.helpers.PipAppHelper
 
 abstract class PipTestBase(
@@ -27,24 +25,6 @@
 ) : NonRotationTestBase(rotationName, rotation) {
     protected val testApp = PipAppHelper(instrumentation)
 
-    protected fun WmAssertion.pipWindowBecomesVisible() {
-        all("pipWindowBecomesVisible") {
-            this.skipUntilFirstAssertion()
-                    .showsAppWindowOnTop(sPipWindowTitle)
-                    .then()
-                    .hidesAppWindow(sPipWindowTitle)
-        }
-    }
-
-    protected fun LayersAssertion.pipLayerBecomesVisible() {
-        all("pipLayerBecomesVisible") {
-            this.skipUntilFirstAssertion()
-                    .showsLayer(sPipWindowTitle)
-                    .then()
-                    .hidesLayer(sPipWindowTitle)
-        }
-    }
-
     companion object {
         const val sPipWindowTitle = "PipMenuActivity"
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
index e5a73f7..04c2f59 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.LargeTest
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.expandPipWindow
 import com.android.server.wm.flicker.helpers.hasPipWindow
@@ -55,35 +56,42 @@
             withTag { buildTestTag("exitPipModeToApp", testApp, rotation) }
             repeat { 1 }
             setup {
-                eachRun {
+                test {
                     device.wakeUpAndGoToHomeScreen()
+                    device.pressHome()
+                    testApp.open()
+                }
+                eachRun {
+                    this.setRotation(rotation)
+                    testApp.clickEnterPipButton(device)
+                    device.hasPipWindow()
                 }
             }
             teardown {
                 eachRun {
-                    testApp.exit()
                     this.setRotation(Surface.ROTATION_0)
                 }
                 test {
                     if (device.hasPipWindow()) {
                         device.closePipWindow()
                     }
+                    testApp.exit()
                 }
             }
             transitions {
-                device.pressHome()
-                this.setRotation(rotation)
-                testApp.open()
-                testApp.clickEnterPipButton(device)
                 device.expandPipWindow()
                 device.waitForIdle()
-                testApp.exit()
             }
             assertions {
                 windowManagerTrace {
                     navBarWindowIsAlwaysVisible()
                     statusBarWindowIsAlwaysVisible()
-                    pipWindowBecomesVisible()
+
+                    all("appReplacesPipWindow") {
+                        this.showsAppWindow(sPipWindowTitle)
+                                .then()
+                                .showsAppWindowOnTop(testApp.launcherName)
+                    }
                 }
 
                 layersTrace {
@@ -92,9 +100,20 @@
                     noUncoveredRegions(rotation)
                     navBarLayerRotatesAndScales(rotation)
                     statusBarLayerRotatesScales(rotation)
-                    pipLayerBecomesVisible()
+
+                    all("appReplacesPipLayer") {
+                        this.showsLayer(sPipWindowTitle)
+                                .then()
+                                .showsLayer(testApp.launcherName)
+                    }
+                }
+
+                eventLog {
+                    focusChanges(
+                            "NexusLauncherActivity", testApp.launcherName, "NexusLauncherActivity",
+                            bugId = 151179149)
                 }
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
index f6d9ce2..b6074cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.LargeTest
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.hasPipWindow
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -54,54 +55,74 @@
             withTag { buildTestTag("exitPipModeToApp", testApp, rotation) }
             repeat { 1 }
             setup {
-                eachRun {
+                test {
                     device.wakeUpAndGoToHomeScreen()
                     device.pressHome()
-                    this.setRotation(rotation)
+                }
+                eachRun {
                     testApp.open()
+                    this.setRotation(rotation)
+                    testApp.clickEnterPipButton(device)
+                    device.hasPipWindow()
                 }
             }
             teardown {
                 eachRun {
-                    testApp.exit()
                     this.setRotation(Surface.ROTATION_0)
+                    if (device.hasPipWindow()) {
+                        device.closePipWindow()
+                    }
                 }
                 test {
                     if (device.hasPipWindow()) {
                         device.closePipWindow()
                     }
+                    testApp.exit()
                 }
             }
             transitions {
-                testApp.clickEnterPipButton(device)
                 testApp.closePipWindow(device)
-                device.waitForIdle()
-                testApp.exit()
             }
             assertions {
                 windowManagerTrace {
                     navBarWindowIsAlwaysVisible()
                     statusBarWindowIsAlwaysVisible()
-                    pipWindowBecomesVisible()
 
-                    all {
-                        this.showsAppWindowOnTop(sPipWindowTitle)
-                                .and()
-                                .showsBelowAppWindow("Wallpaper")
+                    all("pipWindowBecomesInvisible") {
+                        this.showsAppWindow(sPipWindowTitle)
                                 .then()
-                                .showsAboveAppWindow("Wallpaper")
+                                .hidesAppWindow(sPipWindowTitle)
                     }
                 }
 
                 layersTrace {
                     navBarLayerIsAlwaysVisible()
                     statusBarLayerIsAlwaysVisible()
-                    noUncoveredRegions(rotation)
+                    // The final state is the launcher, so always in portrait mode
+                    noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
                     navBarLayerRotatesAndScales(rotation)
                     statusBarLayerRotatesScales(rotation)
-                    pipLayerBecomesVisible()
+
+                    all("pipLayerBecomesInvisible") {
+                        this.showsLayer(sPipWindowTitle)
+                                .then()
+                                .hidesLayer(sPipWindowTitle)
+                    }
+                }
+
+                eventLog {
+                    focusChanges(testApp.launcherName, "NexusLauncherActivity", bugId = 151179149)
                 }
             }
         }
     }
+
+    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/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 239c082..5e75e4a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -22,6 +22,7 @@
 import com.android.server.wm.flicker.RotationTestBase
 import com.android.server.wm.flicker.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -61,25 +62,29 @@
             }
             repeat { 1 }
             setup {
-                eachRun {
+                test {
                     device.wakeUpAndGoToHomeScreen()
                     testApp.open()
+                }
+                eachRun {
                     this.setRotation(beginRotation)
                 }
             }
             teardown {
                 eachRun {
-                    testApp.exit()
                     this.setRotation(Surface.ROTATION_0)
                 }
+                test {
+                    testApp.exit()
+                }
             }
             transitions {
                 this.setRotation(endRotation)
             }
             assertions {
                 windowManagerTrace {
-                    navBarWindowIsAlwaysVisible(bugId = 140855415)
-                    statusBarWindowIsAlwaysVisible(bugId = 140855415)
+                    navBarWindowIsAlwaysVisible()
+                    statusBarWindowIsAlwaysVisible()
                 }
 
                 layersTrace {
@@ -102,23 +107,18 @@
                         this.hasVisibleRegion(testApp.getPackage(), endingPos)
                     }
 
-                    all("screenshotLayerBecomesInvisible", enabled = false) {
+                    all("screenshotLayerBecomesInvisible") {
                         this.showsLayer(testApp.getPackage())
                                 .then()
-                                .replaceVisibleLayer(
-                                        testApp.getPackage(),
-                                        SCREENSHOT_LAYER)
-                                .then()
-                                .showsLayer(testApp.getPackage())
-                                .and()
                                 .showsLayer(SCREENSHOT_LAYER)
                                 .then()
-                                .replaceVisibleLayer(
-                                        SCREENSHOT_LAYER,
-                                        testApp.getPackage()
-                                )
+                                showsLayer(testApp.getPackage())
                     }
                 }
+
+                eventLog {
+                    focusDoesNotChange(bugId = 151179149)
+                }
             }
         }
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 4746376..de87b41 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -24,6 +24,8 @@
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.RotationTestBase
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.dsl.flicker
 import com.android.server.wm.flicker.helpers.stopPackage
@@ -128,14 +130,18 @@
                         val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
                         val endingBounds = WindowUtils.getDisplayBounds(endRotation)
                         if (startingBounds == endingBounds) {
-                            this.coversRegion(startingBounds)
+                            this.coversAtLeastRegion(startingBounds)
                         } else {
-                            this.coversRegion(startingBounds)
+                            this.coversAtLeastRegion(startingBounds)
                                     .then()
-                                    .coversRegion(endingBounds)
+                                    .coversAtLeastRegion(endingBounds)
                         }
                     }
                 }
+
+                eventLog {
+                    focusDoesNotChange(bugId = 151179149)
+                }
             }
         }
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 7c19696..e078f26 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -16,13 +16,14 @@
 
 package com.android.server.wm.flicker.splitscreen
 
-import android.os.SystemClock
 import android.view.Surface
 import androidx.test.filters.LargeTest
 import com.android.server.wm.flicker.NonRotationTestBase
 import com.android.server.wm.flicker.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
 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.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -58,16 +59,21 @@
             withTag { buildTestTag("appToSplitScreen", testApp, rotation) }
             repeat { 1 }
             setup {
-                eachRun {
+                test {
                     device.wakeUpAndGoToHomeScreen()
-                    this.setRotation(rotation)
+                }
+                eachRun {
                     testApp.open()
-                    SystemClock.sleep(500)
+                    this.setRotation(rotation)
                 }
             }
             teardown {
                 eachRun {
-                    device.exitSplitScreen()
+                    if (device.isInSplitScreen()) {
+                        device.exitSplitScreen()
+                    }
+                }
+                test {
                     testApp.exit()
                 }
             }
@@ -93,6 +99,11 @@
                                 .showsLayer(DOCKED_STACK_DIVIDER)
                     }
                 }
+
+                eventLog {
+                    focusChanges(testApp.`package`,
+                            "recents_animation_input_consumer", "NexusLauncherActivity")
+                }
             }
         }
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
index a93330d..a08b2bf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -19,15 +19,16 @@
 import android.graphics.Region
 import android.util.Rational
 import android.view.Surface
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.LargeTest
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.uiautomator.By
 import com.android.server.wm.flicker.FlickerTestBase
 import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.ImeAppHelper
+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
@@ -171,6 +172,10 @@
                                 .hasVisibleRegion(sImeActivity, bottomAppBounds)
                     }
                 }
+
+                eventLog {
+                    focusDoesNotChange()
+                }
             }
         }
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
index 268ba9e..e2d7839 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.splitscreen
 
 import android.view.Surface
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.FlickerTestBase
+import com.android.server.wm.flicker.NonRotationTestBase
 import com.android.server.wm.flicker.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.exitSplitScreen
 import com.android.server.wm.flicker.helpers.isInSplitScreen
 import com.android.server.wm.flicker.helpers.launchSplitScreen
@@ -37,16 +37,19 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
 
 /**
  * Test open app to split screen.
  * To run this test: `atest FlickerTests:SplitScreenToLauncherTest`
  */
 @LargeTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SplitScreenToLauncherTest : FlickerTestBase() {
-    private val rotation: Int = Surface.ROTATION_0
+class SplitScreenToLauncherTest(
+    rotationName: String,
+    rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
     @Test
     fun test() {
         val testApp = StandardAppHelper(instrumentation,
@@ -56,8 +59,10 @@
             withTag { buildTestTag("splitScreenToLauncher", testApp, rotation) }
             repeat { 1 }
             setup {
-                eachRun {
+                test {
                     device.wakeUpAndGoToHomeScreen()
+                }
+                eachRun {
                     testApp.open()
                     this.setRotation(rotation)
                     device.launchSplitScreen()
@@ -103,7 +108,21 @@
                             .hidesLayer(testApp.getPackage())
                     }
                 }
+
+                eventLog {
+                    focusDoesNotChange(bugId = 151179149)
+                }
             }
         }
     }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> {
+            // b/161435597 causes the test not to work on 90 degrees
+            val supportedRotations = intArrayOf(Surface.ROTATION_0)
+            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+        }
+    }
 }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 51bae3a..08144c8 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -60,7 +60,7 @@
 
         static final String sSkSL =
                 "uniform float param1;\n"
-                + "void main(float x, float y, inout half4 color) {\n"
+                + "void main(float2 xy, inout half4 color) {\n"
                 + "color = half4(color.r, half(param1), color.b, 1.0);\n"
                 + "}\n";
 
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
new file mode 100644
index 0000000..9d35cbc
--- /dev/null
+++ b/tests/Input/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+    name: "InputTests",
+    srcs: ["src/**/*.kt"],
+    platform_apis: true,
+    certificate: "platform",
+    static_libs: [
+            "androidx.test.ext.junit",
+            "androidx.test.rules",
+            "android-support-test",
+            "ub-uiautomator",
+        ],
+}
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
new file mode 100644
index 0000000..4195df7
--- /dev/null
+++ b/tests/Input/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?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.test.input">
+    <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+
+    <application android:label="InputTest">
+
+        <activity android:name=".UnresponsiveGestureMonitorActivity"
+             android:label="Unresponsive gesture monitor"
+             android:process=":externalProcess">
+        </activity>
+
+
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.test.input"
+                     android:label="Input Tests"/>
+</manifest>
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
new file mode 100644
index 0000000..c62db1ea
--- /dev/null
+++ b/tests/Input/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs Input Tests">
+    <option name="test-tag" value="InputTests" />
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+        <!-- keeps the screen on during tests -->
+        <option name="screen-always-on" value="on" />
+        <!-- prevents the phone from restarting -->
+        <option name="force-skip-system-props" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="InputTests.apk"/>
+
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.test.input"/>
+        <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+        <option name="shell-timeout" value="660s" />
+        <option name="test-timeout" value="600s" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
new file mode 100644
index 0000000..4da3eca
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -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.test.input
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.MediumTest
+
+import android.graphics.Rect
+import android.os.SystemClock
+import android.provider.Settings
+import android.provider.Settings.Global.HIDE_ERROR_DIALOGS
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiObject2
+import android.support.test.uiautomator.Until
+import android.view.InputDevice
+import android.view.MotionEvent
+
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * This test makes sure that an unresponsive gesture monitor gets an ANR.
+ *
+ * The gesture monitor must be registered from a different process than the instrumented process.
+ * Otherwise, when the test runs, you will get:
+ * Test failed to run to completion.
+ * Reason: 'Instrumentation run failed due to 'keyDispatchingTimedOut''.
+ * Check device logcat for details
+ * RUNNER ERROR: Instrumentation run failed due to 'keyDispatchingTimedOut'
+ */
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class AnrTest {
+    companion object {
+        private const val TAG = "AnrTest"
+    }
+
+    val mInstrumentation = InstrumentationRegistry.getInstrumentation()
+    var mHideErrorDialogs = 0
+
+    @Before
+    fun setUp() {
+        val contentResolver = mInstrumentation.targetContext.contentResolver
+        mHideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+        Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+    }
+
+    @After
+    fun tearDown() {
+        val contentResolver = mInstrumentation.targetContext.contentResolver
+        Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, mHideErrorDialogs)
+    }
+
+    @Test
+    fun testGestureMonitorAnr() {
+        startUnresponsiveActivity()
+        val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+        val obj: UiObject2? = uiDevice.wait(Until.findObject(
+                By.text("Unresponsive gesture monitor")), 10000)
+
+        if (obj == null) {
+            fail("Could not find unresponsive activity")
+            return
+        }
+
+        val rect: Rect = obj.visibleBounds
+        val downTime = SystemClock.uptimeMillis()
+        val downEvent = MotionEvent.obtain(downTime, downTime,
+                MotionEvent.ACTION_DOWN, rect.left.toFloat(), rect.top.toFloat(), 0 /* metaState */)
+        downEvent.source = InputDevice.SOURCE_TOUCHSCREEN
+
+        mInstrumentation.uiAutomation.injectInputEvent(downEvent, false /* sync*/)
+
+        // Todo: replace using timeout from android.hardware.input.IInputManager
+        SystemClock.sleep(5000) // default ANR timeout for gesture monitors
+
+        clickCloseAppOnAnrDialog()
+    }
+
+    private fun clickCloseAppOnAnrDialog() {
+        // Find anr dialog and kill app
+        val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+        val closeAppButton: UiObject2? =
+                uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+        if (closeAppButton == null) {
+            fail("Could not find anr dialog")
+            return
+        }
+        closeAppButton.click()
+    }
+
+    private fun startUnresponsiveActivity() {
+        val flags = " -W -n "
+        val startCmd = "am start $flags com.android.test.input/.UnresponsiveGestureMonitorActivity"
+        mInstrumentation.uiAutomation.executeShellCommand(startCmd)
+    }
+}
\ No newline at end of file
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
new file mode 100644
index 0000000..d83a457
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -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.test.input
+
+import android.app.Activity
+import android.hardware.input.InputManager
+import android.os.Bundle
+import android.os.Looper
+import android.util.Log
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputMonitor
+
+class UnresponsiveReceiver(channel: InputChannel, looper: Looper) :
+        InputEventReceiver(channel, looper) {
+    companion object {
+        const val TAG = "UnresponsiveReceiver"
+    }
+    override fun onInputEvent(event: InputEvent) {
+        Log.i(TAG, "Received $event")
+        // Not calling 'finishInputEvent' in order to trigger the ANR
+    }
+}
+
+class UnresponsiveGestureMonitorActivity : Activity() {
+    companion object {
+        const val MONITOR_NAME = "unresponsive gesture monitor"
+    }
+    private lateinit var mInputEventReceiver: InputEventReceiver
+    private lateinit var mInputMonitor: InputMonitor
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        mInputMonitor = InputManager.getInstance().monitorGestureInput(MONITOR_NAME, displayId)
+        mInputEventReceiver = UnresponsiveReceiver(
+                mInputMonitor.getInputChannel(), Looper.myLooper())
+    }
+}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index da6018e..530d0e4 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -29,6 +29,7 @@
         "compatibility-tradefed",
         "frameworks-base-hostutils",
         "module_test_util",
+        "cts-install-lib-host",
     ],
     data: [
         ":com.android.apex.cts.shim.v2_prebuilt",
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 7cfbdc2..5285b04 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.cts.install.lib.host.InstallUtilsHost;
 import com.android.ddmlib.Log;
 import com.android.tests.rollback.host.AbandonSessionsRule;
 import com.android.tests.util.ModuleTestUtils;
@@ -49,6 +50,7 @@
     private static final String APK_A = "TestAppAv1.apk";
 
     private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this);
+    private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
 
     /**
      * Runs the given phase of a test by calling into the device.
@@ -93,7 +95,7 @@
     @Test
     public void testAdbStagedInstallWaitForReadyFlagWorks() throws Exception {
         assumeTrue("Device does not support updating APEX",
-                mTestUtils.isApexUpdateSupported());
+                mHostUtils.isApexUpdateSupported());
 
         File apexFile = mTestUtils.getTestFile(SHIM_V2);
         String output = getDevice().executeAdbCommand("install", "--staged",
@@ -107,7 +109,7 @@
     @Test
     public void testAdbStagedInstallNoWaitFlagWorks() throws Exception {
         assumeTrue("Device does not support updating APEX",
-                mTestUtils.isApexUpdateSupported());
+                mHostUtils.isApexUpdateSupported());
 
         File apexFile = mTestUtils.getTestFile(SHIM_V2);
         String output = getDevice().executeAdbCommand("install", "--staged",
@@ -122,7 +124,7 @@
     @Test
     public void testAdbInstallMultiPackageCommandWorks() throws Exception {
         assumeTrue("Device does not support updating APEX",
-                mTestUtils.isApexUpdateSupported());
+                mHostUtils.isApexUpdateSupported());
 
         File apexFile = mTestUtils.getTestFile(SHIM_V2);
         File apkFile = mTestUtils.getTestFile(APK_A);
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index eb0a867..a384687 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -28,6 +28,7 @@
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.os.Process.SYSTEM_UID;
 
 import static com.android.server.connectivity.PermissionMonitor.NETWORK;
@@ -138,17 +139,10 @@
         verify(mMockPmi).getPackageList(mPermissionMonitor);
     }
 
-    /**
-     * Remove all permissions from the uid then build new package info and setup permissions to uid
-     * for checking restricted network permission.
-     */
-    private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
-            String... permissions) {
+    private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) {
         final PackageInfo packageInfo = buildPackageInfo(partition, uid, MOCK_USER1);
         packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
-        removeAllPermissions(uid);
-        addPermissions(uid, permissions);
-        return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo.applicationInfo);
+        return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo);
     }
 
     private static PackageInfo packageInfoWithPartition(String partition) {
@@ -228,61 +222,57 @@
         assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
     }
 
+    /**
+     * Remove all permissions from the uid then setup permissions to uid for checking restricted
+     * network permission.
+     */
+    private void assertRestrictedNetworkPermission(boolean hasPermission, int uid,
+            String... permissions) {
+        removeAllPermissions(uid);
+        addPermissions(uid, permissions);
+        assertEquals(hasPermission, mPermissionMonitor.hasRestrictedNetworkPermission(uid));
+    }
+
     @Test
     public void testHasRestrictedNetworkPermission() {
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
-        assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
-        assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
-        assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+        assertRestrictedNetworkPermission(false, MOCK_UID1);
+        assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_NETWORK_STATE);
+        assertRestrictedNetworkPermission(true, MOCK_UID1, NETWORK_STACK);
+        assertRestrictedNetworkPermission(false, MOCK_UID1, CONNECTIVITY_INTERNAL);
+        assertRestrictedNetworkPermission(true, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+        assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_WIFI_STATE);
+        assertRestrictedNetworkPermission(true, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK);
 
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
-        assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+        assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(MOCK_UID2));
+        assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(SYSTEM_UID));
     }
 
     @Test
-    public void testHasRestrictedNetworkPermissionSystemUid() {
+    public void testIsCarryoverPackage() {
         doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
-        assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+        assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
+        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
+        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
+        assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
+        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
 
         doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
-        assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
-    }
+        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
+        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
+        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
 
-    @Test
-    public void testHasRestrictedNetworkPermissionVendorApp() {
-        assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
-        assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
-
-        assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
-        assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
-        assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1));
+        assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
     }
 
     private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
@@ -296,19 +286,23 @@
 
     @Test
     public void testHasUseBackgroundNetworksPermission() throws Exception {
+        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
+        assertBackgroundPermission(false, "mock1", MOCK_UID1);
+        assertBackgroundPermission(false, "mock2", MOCK_UID1, CONNECTIVITY_INTERNAL);
+        assertBackgroundPermission(true, "mock3", MOCK_UID1, NETWORK_STACK);
+
+        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
+        assertBackgroundPermission(false, "mock4", MOCK_UID2);
+        assertBackgroundPermission(true, "mock5", MOCK_UID2,
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+
         doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
         assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
         assertBackgroundPermission(false, "system1", SYSTEM_UID);
-        assertBackgroundPermission(false, "system2", SYSTEM_UID, CONNECTIVITY_INTERNAL);
-        assertBackgroundPermission(true, "system3", SYSTEM_UID, CHANGE_NETWORK_STATE);
-
-        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
-        assertBackgroundPermission(false, "mock1", MOCK_UID1);
-        assertBackgroundPermission(true, "mock2", MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
-
-        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
-        assertBackgroundPermission(false, "mock3", MOCK_UID2, CONNECTIVITY_INTERNAL);
-        assertBackgroundPermission(true, "mock4", MOCK_UID2, NETWORK_STACK);
+        assertBackgroundPermission(true, "system2", SYSTEM_UID, CHANGE_NETWORK_STATE);
+        doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
+        removeAllPermissions(SYSTEM_UID);
+        assertBackgroundPermission(true, "system3", SYSTEM_UID);
     }
 
     private class NetdMonitor {
diff --git a/tests/utils/DummyIME/Android.bp b/tests/utils/StubIME/Android.bp
similarity index 96%
rename from tests/utils/DummyIME/Android.bp
rename to tests/utils/StubIME/Android.bp
index 4a44b3b..668c92c 100644
--- a/tests/utils/DummyIME/Android.bp
+++ b/tests/utils/StubIME/Android.bp
@@ -15,7 +15,7 @@
 //
 
 android_test {
-    name: "DummyIME",
+    name: "StubIME",
     srcs: ["src/**/*.java"],
     sdk_version: "current",
 }
diff --git a/tests/utils/DummyIME/AndroidManifest.xml b/tests/utils/StubIME/AndroidManifest.xml
similarity index 80%
rename from tests/utils/DummyIME/AndroidManifest.xml
rename to tests/utils/StubIME/AndroidManifest.xml
index 4dc0b57..bc64c67 100644
--- a/tests/utils/DummyIME/AndroidManifest.xml
+++ b/tests/utils/StubIME/AndroidManifest.xml
@@ -18,20 +18,20 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-     package="com.android.testing.dummyime">
+     package="com.android.testing.stubime">
     <application android:label="Dummy IME">
         <service android:name="DummyIme"
-             android:permission="android.permission.BIND_INPUT_METHOD"
-             android:exported="true">
+            android:permission="android.permission.BIND_INPUT_METHOD"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.view.InputMethod"/>
             </intent-filter>
             <meta-data android:name="android.view.im"
-                 android:resource="@xml/method"/>
+                android:resource="@xml/method"/>
         </service>
         <activity android:name=".ImePreferences"
-             android:label="Dummy IME Settings"
-             android:exported="true">
+            android:label="Stub IME Settings"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
             </intent-filter>
diff --git a/tests/utils/DummyIME/res/xml/method.xml b/tests/utils/StubIME/res/xml/method.xml
similarity index 92%
rename from tests/utils/DummyIME/res/xml/method.xml
rename to tests/utils/StubIME/res/xml/method.xml
index 43a330e..1bb4bcd 100644
--- a/tests/utils/DummyIME/res/xml/method.xml
+++ b/tests/utils/StubIME/res/xml/method.xml
@@ -21,9 +21,9 @@
 <!-- for the Search Manager. -->
 
 <input-method xmlns:android="http://schemas.android.com/apk/res/android"
-        android:settingsActivity="com.android.testing.dummyime.ImePreferences">
+        android:settingsActivity="com.android.testing.stubime.ImePreferences">
     <subtype
         android:label="Generic"
         android:imeSubtypeLocale="en_US"
         android:imeSubtypeMode="keyboard" />
-</input-method>
\ No newline at end of file
+</input-method>
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
similarity index 90%
rename from tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
rename to tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
index 41036ab..b77525a 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
 
 import android.preference.PreferenceActivity;
 
 /**
- * Dummy IME preference activity
+ * Stub IME preference activity
  */
 public class ImePreferences extends PreferenceActivity {
 
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
similarity index 85%
rename from tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java
rename to tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
index 7b7a39a..8795202 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
 
 import android.inputmethodservice.InputMethodService;
 
 /**
- * Dummy IME implementation that basically does nothing
+ * Stub IME implementation that basically does nothing
  */
-public class DummyIme extends InputMethodService {
+public class StubIme extends InputMethodService {
 
     @Override
     public boolean onEvaluateFullscreenMode() {
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 931a14b..3d9be59 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -342,7 +342,7 @@
     }
   }
 
-  // Sanity check to make sure we processed all the nodes.
+  // Validity check to make sure we processed all the nodes.
   CHECK(node_stack.size() == 1u);
   CHECK(node_stack.back() == &root);
 
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 469128b..7dfc983 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -740,7 +740,7 @@
   if (type == ResourceType::kId) {
     if (res_value.dataType != android::Res_value::TYPE_REFERENCE &&
         res_value.dataType != android::Res_value::TYPE_DYNAMIC_REFERENCE) {
-      // plain "id" resources are actually encoded as dummy values (aapt1 uses an empty string,
+      // plain "id" resources are actually encoded as unused values (aapt1 uses an empty string,
       // while aapt2 uses a false boolean).
       return util::make_unique<Id>();
     }
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index ab9ce66..b1e1a77 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -168,6 +168,7 @@
     ODM = 6;
     OEM = 7;
     ACTOR = 8;
+    CONFIG_SIGNATURE = 9;
   }
 
   // The location of the <item> declaration in source.
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index fb7f6d7..f9c54f6 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1401,7 +1401,7 @@
     return MergeExportedSymbols(compiled_file.source, compiled_file.exported_symbols);
   }
 
-  // Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
+  // Takes a path to load as a ZIP file and merges the files within into the main ResourceTable.
   // If override is true, conflicting resources are allowed to override each other, in order of last
   // seen.
   // An io::IFileCollection is created from the ZIP file and added to the set of
@@ -1432,7 +1432,7 @@
     return !error;
   }
 
-  // Takes a path to load and merge into the master ResourceTable. If override is true,
+  // Takes a path to load and merge into the main ResourceTable. If override is true,
   // conflicting resources are allowed to override each other, in order of last seen.
   // If the file path ends with .flata, .jar, .jack, or .zip the file is treated
   // as ZIP archive and the files within are merged individually.
@@ -1449,7 +1449,7 @@
     return MergeFile(file, override);
   }
 
-  // Takes an AAPT Container file (.apc/.flat) to load and merge into the master ResourceTable.
+  // Takes an AAPT Container file (.apc/.flat) to load and merge into the main ResourceTable.
   // If override is true, conflicting resources are allowed to override each other, in order of last
   // seen.
   // All other file types are ignored. This is because these files could be coming from a zip,
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index e36668e..5b18a37 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -132,8 +132,8 @@
     if (context_->IsVerbose()) {
       context_->GetDiagnostics()->Note(DiagMessage() << "Optimizing APK...");
     }
-    if (!options_.resources_blacklist.empty()) {
-      ResourceFilter filter(options_.resources_blacklist);
+    if (!options_.resources_exclude_list.empty()) {
+      ResourceFilter filter(options_.resources_exclude_list);
       if (!filter.Consume(context_, apk->GetResourceTable())) {
         context_->GetDiagnostics()->Error(DiagMessage() << "failed filtering resources");
         return 1;
@@ -328,7 +328,7 @@
     }
     for (StringPiece directive : util::Tokenize(directives, ',')) {
       if (directive == "remove") {
-        options->resources_blacklist.insert(resource_name.ToResourceName());
+        options->resources_exclude_list.insert(resource_name.ToResourceName());
       } else if (directive == "no_collapse" || directive == "no_obfuscate") {
         options->table_flattener_options.name_collapse_exemptions.insert(
             resource_name.ToResourceName());
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index 5070ccc..3afc46b 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -36,8 +36,8 @@
   // Details of the app extracted from the AndroidManifest.xml
   AppInfo app_info;
 
-  // Blacklist of unused resources that should be removed from the apk.
-  std::unordered_set<ResourceName> resources_blacklist;
+  // Exclude list of unused resources that should be removed from the apk.
+  std::unordered_set<ResourceName> resources_exclude_list;
 
   // Split APK options.
   TableSplitterOptions table_splitter_options;
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
index bc2e699..4db2392 100644
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -35,7 +35,7 @@
          ((uint32_t)d);
 }
 
-// Whitelist of PNG chunk types that we want to keep in the resulting PNG.
+// Allow list of PNG chunk types that we want to keep in the resulting PNG.
 enum PngChunkTypes {
   kPngChunkIHDR = u32(73, 72, 68, 82),
   kPngChunkIDAT = u32(73, 68, 65, 84),
@@ -56,7 +56,7 @@
   return word;
 }
 
-static bool IsPngChunkWhitelisted(uint32_t type) {
+static bool IsPngChunkAllowed(uint32_t type) {
   switch (type) {
     case kPngChunkIHDR:
     case kPngChunkIDAT:
@@ -128,7 +128,7 @@
 
     // Do we strip this chunk?
     const uint32_t chunk_type = Peek32LE(data_.data() + window_end_ + sizeof(uint32_t));
-    if (IsPngChunkWhitelisted(chunk_type)) {
+    if (IsPngChunkAllowed(chunk_type)) {
       // Advance the window to include this chunk.
       window_end_ += kMinChunkHeaderSize + chunk_len;
 
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 2ef8b99..e5b3107 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -187,7 +187,7 @@
 
 TEST_F(ConfigurationParserTest, ExtractConfiguration) {
   Maybe<PostProcessingConfiguration> maybe_config =
-      ExtractConfiguration(kValidConfig, "dummy.xml", &diag_);
+      ExtractConfiguration(kValidConfig, "fake.xml", &diag_);
 
   PostProcessingConfiguration config = maybe_config.value();
 
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 53d9ffe..71c70da 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -188,7 +188,7 @@
 
     /** Retrieves the resource assigned to the specified resource id if one exists. */
     Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
-                         const ConfigDescription& config = DummyConfig()) {
+                         const ConfigDescription& config = DefaultConfig()) {
       if (table) {
         for (auto& package : table->packages) {
           if (package->id && package->id.value() == res_id.package_id()) {
@@ -210,7 +210,7 @@
     }
 
     /** Attempts to resolve the reference to a non-reference value. */
-    Value* ResolveReference(Reference* ref, const ConfigDescription& config = DummyConfig()) {
+    Value* ResolveReference(Reference* ref, const ConfigDescription& config = DefaultConfig()) {
       const int kMaxIterations = 40;
       int i = 0;
       while (ref && ref->id && i++ < kMaxIterations) {
@@ -231,10 +231,10 @@
      * this will attempt to resolve the reference to an integer value.
      **/
     int32_t* GetAttributeInteger(xml::Attribute* attr,
-                                 const ConfigDescription& config = DummyConfig()) {
+                                 const ConfigDescription& config = DefaultConfig()) {
       if (attr != nullptr) {
         if (attr->compiled_value) {
-          // Resolve references using the dummy configuration
+          // Resolve references using the configuration
           Value* value = attr->compiled_value.get();
           if (ValueCast<Reference>(value)) {
             value = ResolveReference(ValueCast<Reference>(value), config);
@@ -257,7 +257,7 @@
      * exist or cannot be resolved to an integer value.
      **/
     int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
-                                       const ConfigDescription& config = DummyConfig()) {
+                                       const ConfigDescription& config = DefaultConfig()) {
       auto value = GetAttributeInteger(attr, config);
       if (value) {
         return *value;
@@ -270,10 +270,10 @@
      * this will attempt to resolve the reference to a string value.
      **/
     const std::string* GetAttributeString(xml::Attribute* attr,
-                                          const ConfigDescription& config = DummyConfig()) {
+                                          const ConfigDescription& config = DefaultConfig()) {
       if (attr != nullptr) {
         if (attr->compiled_value) {
-          // Resolve references using the dummy configuration
+          // Resolve references using the configuration
           Value* value = attr->compiled_value.get();
           if (ValueCast<Reference>(value)) {
             value = ResolveReference(ValueCast<Reference>(value), config);
@@ -305,7 +305,7 @@
      * exist or cannot be resolved to an string value.
      **/
     std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
-                                          const ConfigDescription& config = DummyConfig()) {
+                                          const ConfigDescription& config = DefaultConfig()) {
       auto value = GetAttributeString(attr, config);
       if (value) {
         return *value;
@@ -322,7 +322,7 @@
   friend Element;
 
   /** Creates a default configuration used to retrieve resources. */
-  static ConfigDescription DummyConfig() {
+  static ConfigDescription DefaultConfig() {
     ConfigDescription config;
     config.orientation = android::ResTable_config::ORIENTATION_PORT;
     config.density = android::ResTable_config::DENSITY_MEDIUM;
@@ -1871,7 +1871,7 @@
 
             // Collect all the unique locales of the apk
             if (locales_.find(locale_str) == locales_.end()) {
-              ConfigDescription config = ManifestExtractor::DummyConfig();
+              ConfigDescription config = ManifestExtractor::DefaultConfig();
               config.setBcp47Locale(locale_str.data());
               locales_.insert(std::make_pair(locale_str, config));
             }
@@ -1880,7 +1880,7 @@
             uint16_t density = (value->config.density == 0) ? (uint16_t) 160
                                                             : value->config.density;
             if (densities_.find(density) == densities_.end()) {
-              ConfigDescription config = ManifestExtractor::DummyConfig();
+              ConfigDescription config = ManifestExtractor::DefaultConfig();
               config.density = density;
               densities_.insert(std::make_pair(density, config));
             }
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 59627ce..6932baf 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -776,6 +776,7 @@
   OverlayableItem overlayable_item_three(group_one);
   overlayable_item_three.policies |= PolicyFlags::SIGNATURE;
   overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE;
+  overlayable_item_three.policies |= PolicyFlags::CONFIG_SIGNATURE;
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
@@ -830,7 +831,8 @@
   EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
   EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE
-                                           | PolicyFlags::ACTOR_SIGNATURE);
+                                           | PolicyFlags::ACTOR_SIGNATURE
+                                           | PolicyFlags::CONFIG_SIGNATURE);
 }
 
 TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 582bd39..06ac9e5 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -404,6 +404,9 @@
       case pb::OverlayableItem::ACTOR:
         out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE;
         break;
+      case pb::OverlayableItem::CONFIG_SIGNATURE:
+        out_overlayable->policies |= PolicyFlags::CONFIG_SIGNATURE;
+        break;
       default:
         *out_error = "unknown overlayable policy";
         return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 5ab43b7..98c5175 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -325,6 +325,9 @@
   if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR);
   }
+  if (overlayable_item.policies & PolicyFlags::CONFIG_SIGNATURE) {
+    pb_overlayable_item->add_policy(pb::OverlayableItem::CONFIG_SIGNATURE);
+  }
 
   if (source_pool != nullptr) {
     SerializeSourceToPb(overlayable_item.source, source_pool,
diff --git a/tools/aapt2/jni/aapt2_jni.cpp b/tools/aapt2/jni/aapt2_jni.cpp
index ba9646f..ec3c543 100644
--- a/tools/aapt2/jni/aapt2_jni.cpp
+++ b/tools/aapt2/jni/aapt2_jni.cpp
@@ -139,5 +139,5 @@
 
 JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping(
         JNIEnv *env, jclass aapt_obj) {
-  // This is just a dummy method to see if the library has been loaded.
+  // This is just a no-op method to see if the library has been loaded.
 }
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 49f8e1b..dac21d7 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -570,8 +570,8 @@
   }
 
   xml::XmlActionExecutorPolicy policy = options_.warn_validation
-                                            ? xml::XmlActionExecutorPolicy::kWhitelistWarning
-                                            : xml::XmlActionExecutorPolicy::kWhitelist;
+                                            ? xml::XmlActionExecutorPolicy::kAllowListWarning
+                                            : xml::XmlActionExecutorPolicy::kAllowList;
   if (!executor.Execute(policy, context->GetDiagnostics(), doc)) {
     return false;
   }
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index c25e450..ad56092 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -31,11 +31,11 @@
 
 TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
                          const TableMergerOptions& options)
-    : context_(context), master_table_(out_table), options_(options) {
+    : context_(context), main_table_(out_table), options_(options) {
   // Create the desired package that all tables will be merged into.
-  master_package_ =
-      master_table_->CreatePackage(context_->GetCompilationPackage(), context_->GetPackageId());
-  CHECK(master_package_ != nullptr) << "package name or ID already taken";
+  main_package_ =
+      main_table_->CreatePackage(context_->GetCompilationPackage(), context_->GetPackageId());
+  CHECK(main_package_ != nullptr) << "package name or ID already taken";
 }
 
 bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
@@ -235,7 +235,7 @@
   bool error = false;
 
   for (auto& src_type : src_package->types) {
-    ResourceTableType* dst_type = master_package_->FindOrCreateType(src_type->type);
+    ResourceTableType* dst_type = main_package_->FindOrCreateType(src_type->type);
     if (!MergeType(context_, src, dst_type, src_type.get())) {
       error = true;
       continue;
@@ -279,7 +279,7 @@
         if (dst_config_value) {
           CollisionResult collision_result = MergeConfigValue(
               context_, res_name, overlay, options_.override_styles_instead_of_overlaying,
-              dst_config_value, src_config_value.get(), &master_table_->string_pool);
+              dst_config_value, src_config_value.get(), &main_table_->string_pool);
           if (collision_result == CollisionResult::kConflict) {
             error = true;
             continue;
@@ -298,7 +298,7 @@
           if (mangle_package) {
             new_file_ref = CloneAndMangleFile(src_package->name, *f);
           } else {
-            new_file_ref = std::unique_ptr<FileReference>(f->Clone(&master_table_->string_pool));
+            new_file_ref = std::unique_ptr<FileReference>(f->Clone(&main_table_->string_pool));
           }
           dst_config_value->value = std::move(new_file_ref);
 
@@ -307,7 +307,7 @@
               ? dst_config_value->value->GetComment() : Maybe<std::string>();
 
           dst_config_value->value = std::unique_ptr<Value>(
-              src_config_value->value->Clone(&master_table_->string_pool));
+              src_config_value->value->Clone(&main_table_->string_pool));
 
           // Keep the comment from the original resource and ignore all comments from overlaying
           // resources
@@ -328,14 +328,14 @@
     std::string mangled_entry = NameMangler::MangleEntry(package, entry.to_string());
     std::string newPath = prefix.to_string() + mangled_entry + suffix.to_string();
     std::unique_ptr<FileReference> new_file_ref =
-        util::make_unique<FileReference>(master_table_->string_pool.MakeRef(newPath));
+        util::make_unique<FileReference>(main_table_->string_pool.MakeRef(newPath));
     new_file_ref->SetComment(file_ref.GetComment());
     new_file_ref->SetSource(file_ref.GetSource());
     new_file_ref->type = file_ref.type;
     new_file_ref->file = file_ref.file;
     return new_file_ref;
   }
-  return std::unique_ptr<FileReference>(file_ref.Clone(&master_table_->string_pool));
+  return std::unique_ptr<FileReference>(file_ref.Clone(&main_table_->string_pool));
 }
 
 bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFile* file) {
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index a35a134..e01a0c1 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -80,9 +80,9 @@
   DISALLOW_COPY_AND_ASSIGN(TableMerger);
 
   IAaptContext* context_;
-  ResourceTable* master_table_;
+  ResourceTable* main_table_;
   TableMergerOptions options_;
-  ResourceTablePackage* master_package_;
+  ResourceTablePackage* main_package_;
   std::set<std::string> merged_packages_;
 
   bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
diff --git a/tools/aapt2/link/XmlCompatVersioner.cpp b/tools/aapt2/link/XmlCompatVersioner.cpp
index 20ebdc6..6937ca9 100644
--- a/tools/aapt2/link/XmlCompatVersioner.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner.cpp
@@ -143,8 +143,8 @@
 
   // Iterate from smallest to largest API version.
   for (ApiVersion api : apis_referenced) {
-    std::set<ApiVersion> dummy;
-    versioned_docs.push_back(ProcessDoc(api, api_range.end, doc, &dummy));
+    std::set<ApiVersion> tmp;
+    versioned_docs.push_back(ProcessDoc(api, api_range.end, doc, &tmp));
   }
   return versioned_docs;
 }
diff --git a/tools/aapt2/optimize/ResourceFilter.cpp b/tools/aapt2/optimize/ResourceFilter.cpp
index 250b651..08c045b 100644
--- a/tools/aapt2/optimize/ResourceFilter.cpp
+++ b/tools/aapt2/optimize/ResourceFilter.cpp
@@ -20,8 +20,8 @@
 
 namespace aapt {
 
-ResourceFilter::ResourceFilter(const std::unordered_set<ResourceName>& blacklist)
-    : blacklist_(blacklist) {
+ResourceFilter::ResourceFilter(const std::unordered_set<ResourceName>& exclude_list)
+    : exclude_list_(exclude_list) {
 }
 
 bool ResourceFilter::Consume(IAaptContext* context, ResourceTable* table) {
@@ -29,7 +29,7 @@
     for (auto& type : package->types) {
       for (auto it = type->entries.begin(); it != type->entries.end(); ) {
         ResourceName resource = ResourceName({}, type->type, (*it)->name);
-        if (blacklist_.find(resource) != blacklist_.end()) {
+        if (exclude_list_.find(resource) != exclude_list_.end()) {
           it = type->entries.erase(it);
         } else {
           ++it;
diff --git a/tools/aapt2/optimize/ResourceFilter.h b/tools/aapt2/optimize/ResourceFilter.h
index d4baf65..a264533 100644
--- a/tools/aapt2/optimize/ResourceFilter.h
+++ b/tools/aapt2/optimize/ResourceFilter.h
@@ -25,16 +25,16 @@
 
 namespace aapt {
 
-// Removes non-whitelisted entries from resource table.
+// Removes exclude-listed entries from resource table.
 class ResourceFilter : public IResourceTableConsumer {
  public:
-  explicit ResourceFilter(const std::unordered_set<ResourceName>& blacklist);
+  explicit ResourceFilter(const std::unordered_set<ResourceName>& exclude_list);
 
   bool Consume(IAaptContext* context, ResourceTable* table) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ResourceFilter);
-  std::unordered_set<ResourceName> blacklist_;
+  std::unordered_set<ResourceName> exclude_list_;
 };
 
 } // namespace aapt
diff --git a/tools/aapt2/optimize/ResourceFilter_test.cpp b/tools/aapt2/optimize/ResourceFilter_test.cpp
index ef57f9c..34d8fd2 100644
--- a/tools/aapt2/optimize/ResourceFilter_test.cpp
+++ b/tools/aapt2/optimize/ResourceFilter_test.cpp
@@ -31,22 +31,22 @@
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
-          .AddString("android:string/notblacklisted", ResourceId{}, default_config, "value")
-          .AddString("android:string/blacklisted", ResourceId{}, default_config, "value")
-          .AddString("android:string/notblacklisted2", ResourceId{}, default_config, "value")
-          .AddString("android:string/blacklisted2", ResourceId{}, default_config, "value")
+          .AddString("android:string/notexclude_listed", ResourceId{}, default_config, "value")
+          .AddString("android:string/exclude_listed", ResourceId{}, default_config, "value")
+          .AddString("android:string/notexclude_listed2", ResourceId{}, default_config, "value")
+          .AddString("android:string/exclude_listed2", ResourceId{}, default_config, "value")
           .Build();
 
-  std::unordered_set<ResourceName> blacklist = {
-    ResourceName({}, ResourceType::kString, "blacklisted"),
-    ResourceName({}, ResourceType::kString, "blacklisted2"),
+  std::unordered_set<ResourceName> exclude_list = {
+    ResourceName({}, ResourceType::kString, "exclude_listed"),
+    ResourceName({}, ResourceType::kString, "exclude_listed2"),
   };
 
-  ASSERT_TRUE(ResourceFilter(blacklist).Consume(context.get(), table.get()));
-  EXPECT_THAT(table, HasValue("android:string/notblacklisted", default_config));
-  EXPECT_THAT(table, HasValue("android:string/notblacklisted2", default_config));
-  EXPECT_THAT(table, Not(HasValue("android:string/blacklisted", default_config)));
-  EXPECT_THAT(table, Not(HasValue("android:string/blacklisted2", default_config)));
+  ASSERT_TRUE(ResourceFilter(exclude_list).Consume(context.get(), table.get()));
+  EXPECT_THAT(table, HasValue("android:string/notexclude_listed", default_config));
+  EXPECT_THAT(table, HasValue("android:string/notexclude_listed2", default_config));
+  EXPECT_THAT(table, Not(HasValue("android:string/exclude_listed", default_config)));
+  EXPECT_THAT(table, Not(HasValue("android:string/exclude_listed2", default_config)));
 }
 
 TEST(ResourceFilterTest, TypeIsCheckedBeforeFiltering) {
@@ -55,21 +55,21 @@
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
-          .AddString("android:string/notblacklisted", ResourceId{}, default_config, "value")
-          .AddString("android:string/blacklisted", ResourceId{}, default_config, "value")
-          .AddString("android:drawable/notblacklisted", ResourceId{}, default_config, "value")
-          .AddString("android:drawable/blacklisted", ResourceId{}, default_config, "value")
+          .AddString("android:string/notexclude_listed", ResourceId{}, default_config, "value")
+          .AddString("android:string/exclude_listed", ResourceId{}, default_config, "value")
+          .AddString("android:drawable/notexclude_listed", ResourceId{}, default_config, "value")
+          .AddString("android:drawable/exclude_listed", ResourceId{}, default_config, "value")
           .Build();
 
-  std::unordered_set<ResourceName> blacklist = {
-    ResourceName({}, ResourceType::kString, "blacklisted"),
+  std::unordered_set<ResourceName> exclude_list = {
+    ResourceName({}, ResourceType::kString, "exclude_listed"),
   };
 
-  ASSERT_TRUE(ResourceFilter(blacklist).Consume(context.get(), table.get()));
-  EXPECT_THAT(table, HasValue("android:string/notblacklisted", default_config));
-  EXPECT_THAT(table, HasValue("android:drawable/blacklisted", default_config));
-  EXPECT_THAT(table, HasValue("android:drawable/notblacklisted", default_config));
-  EXPECT_THAT(table, Not(HasValue("android:string/blacklisted", default_config)));
+  ASSERT_TRUE(ResourceFilter(exclude_list).Consume(context.get(), table.get()));
+  EXPECT_THAT(table, HasValue("android:string/notexclude_listed", default_config));
+  EXPECT_THAT(table, HasValue("android:drawable/exclude_listed", default_config));
+  EXPECT_THAT(table, HasValue("android:drawable/notexclude_listed", default_config));
+  EXPECT_THAT(table, Not(HasValue("android:string/exclude_listed", default_config)));
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp
index b54c155..23c2218 100644
--- a/tools/aapt2/test/Common.cpp
+++ b/tools/aapt2/test/Common.cpp
@@ -21,7 +21,7 @@
 namespace aapt {
 namespace test {
 
-struct DummyDiagnosticsImpl : public IDiagnostics {
+struct TestDiagnosticsImpl : public IDiagnostics {
   void Log(Level level, DiagMessageActual& actual_msg) override {
     switch (level) {
       case Level::Note:
@@ -39,7 +39,7 @@
 };
 
 IDiagnostics* GetDiagnostics() {
-  static DummyDiagnosticsImpl diag;
+  static TestDiagnosticsImpl diag;
   return &diag;
 }
 
diff --git a/tools/aapt2/trace/TraceBuffer.h b/tools/aapt2/trace/TraceBuffer.h
index 8618e0e..ba751dd 100644
--- a/tools/aapt2/trace/TraceBuffer.h
+++ b/tools/aapt2/trace/TraceBuffer.h
@@ -40,7 +40,7 @@
 void BeginTrace(const std::string& tag);
 void EndTrace();
 
-// A master trace is required to flush events to disk. Events are formatted in systrace
+// A main trace is required to flush events to disk. Events are formatted in systrace
 // json format.
 class FlushTrace {
 public:
diff --git a/tools/aapt2/util/Maybe_test.cpp b/tools/aapt2/util/Maybe_test.cpp
index 2057ddc..4c921f1 100644
--- a/tools/aapt2/util/Maybe_test.cpp
+++ b/tools/aapt2/util/Maybe_test.cpp
@@ -22,32 +22,32 @@
 
 namespace aapt {
 
-struct Dummy {
-  Dummy() {
+struct Fake {
+  Fake() {
     data = new int;
     *data = 1;
-    std::cerr << "Construct Dummy{0x" << (void*)this << "} with data=0x"
+    std::cerr << "Construct Fake{0x" << (void*)this << "} with data=0x"
               << (void*)data << std::endl;
   }
 
-  Dummy(const Dummy& rhs) {
+  Fake(const Fake& rhs) {
     data = nullptr;
     if (rhs.data) {
       data = new int;
       *data = *rhs.data;
     }
-    std::cerr << "CopyConstruct Dummy{0x" << (void*)this << "} from Dummy{0x"
+    std::cerr << "CopyConstruct Fake{0x" << (void*)this << "} from Fake{0x"
               << (const void*)&rhs << "}" << std::endl;
   }
 
-  Dummy(Dummy&& rhs) {
+  Fake(Fake&& rhs) {
     data = rhs.data;
     rhs.data = nullptr;
-    std::cerr << "MoveConstruct Dummy{0x" << (void*)this << "} from Dummy{0x"
+    std::cerr << "MoveConstruct Fake{0x" << (void*)this << "} from Fake{0x"
               << (const void*)&rhs << "}" << std::endl;
   }
 
-  Dummy& operator=(const Dummy& rhs) {
+  Fake& operator=(const Fake& rhs) {
     delete data;
     data = nullptr;
 
@@ -55,22 +55,22 @@
       data = new int;
       *data = *rhs.data;
     }
-    std::cerr << "CopyAssign Dummy{0x" << (void*)this << "} from Dummy{0x"
+    std::cerr << "CopyAssign Fake{0x" << (void*)this << "} from Fake{0x"
               << (const void*)&rhs << "}" << std::endl;
     return *this;
   }
 
-  Dummy& operator=(Dummy&& rhs) {
+  Fake& operator=(Fake&& rhs) {
     delete data;
     data = rhs.data;
     rhs.data = nullptr;
-    std::cerr << "MoveAssign Dummy{0x" << (void*)this << "} from Dummy{0x"
+    std::cerr << "MoveAssign Fake{0x" << (void*)this << "} from Fake{0x"
               << (const void*)&rhs << "}" << std::endl;
     return *this;
   }
 
-  ~Dummy() {
-    std::cerr << "Destruct Dummy{0x" << (void*)this << "} with data=0x"
+  ~Fake() {
+    std::cerr << "Destruct Fake{0x" << (void*)this << "} with data=0x"
               << (void*)data << std::endl;
     delete data;
   }
@@ -100,15 +100,15 @@
 }
 
 TEST(MaybeTest, Lifecycle) {
-  Maybe<Dummy> val = make_nothing<Dummy>();
+  Maybe<Fake> val = make_nothing<Fake>();
 
-  Maybe<Dummy> val2 = make_value(Dummy());
+  Maybe<Fake> val2 = make_value(Fake());
 }
 
 TEST(MaybeTest, MoveAssign) {
-  Maybe<Dummy> val;
+  Maybe<Fake> val;
   {
-    Maybe<Dummy> val2 = Dummy();
+    Maybe<Fake> val2 = Fake();
     val = std::move(val2);
   }
 }
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index cb844f0..fab17c9 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -74,11 +74,11 @@
         for (const StringPiece& element : *bread_crumb) {
           error_msg << "<" << element << ">";
         }
-        if (policy == XmlActionExecutorPolicy::kWhitelistWarning) {
+        if (policy == XmlActionExecutorPolicy::kAllowListWarning) {
           // Treat the error only as a warning.
           diag->Warn(error_msg);
         } else {
-          // Policy is XmlActionExecutorPolicy::kWhitelist, we should fail.
+          // Policy is XmlActionExecutorPolicy::kAllowList, we should fail.
           diag->Error(error_msg);
           error = true;
         }
@@ -94,7 +94,7 @@
 
   Element* el = doc->root.get();
   if (!el) {
-    if (policy == XmlActionExecutorPolicy::kWhitelist) {
+    if (policy == XmlActionExecutorPolicy::kAllowList) {
       source_diag.Error(DiagMessage() << "no root XML tag found");
       return false;
     }
@@ -109,7 +109,7 @@
       return iter->second.Execute(policy, &bread_crumb, &source_diag, el);
     }
 
-    if (policy == XmlActionExecutorPolicy::kWhitelist) {
+    if (policy == XmlActionExecutorPolicy::kAllowList) {
       DiagMessage error_msg(el->line_number);
       error_msg << "unexpected root element ";
       PrintElementToDiagMessage(el, &error_msg);
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index f689b2a..a0ad1da 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -37,12 +37,12 @@
   // The actions defined must match and run. If an element is found that does not match an action,
   // an error occurs.
   // Note: namespaced elements are always ignored.
-  kWhitelist,
+  kAllowList,
 
   // The actions defined should match and run. if an element is found that does not match an
   // action, a warning is printed.
   // Note: namespaced elements are always ignored.
-  kWhitelistWarning,
+  kAllowListWarning,
 };
 
 // Contains the actions to perform at this XML node. This is a recursive data structure that
diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp
index d39854e..d47b495 100644
--- a/tools/aapt2/xml/XmlActionExecutor_test.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp
@@ -60,10 +60,10 @@
   StdErrDiagnostics diag;
 
   doc = test::BuildXmlDom("<manifest><application /><activity /></manifest>");
-  ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
+  ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kAllowList, &diag, doc.get()));
 
   doc = test::BuildXmlDom("<manifest><application><activity /></application></manifest>");
-  ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
+  ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kAllowList, &diag, doc.get()));
 }
 
 }  // namespace xml
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index f25fcdc..99aaa3c 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -11,7 +11,7 @@
         if (( count == 0 )); then
             echo
         fi
-        echo -e "\033[0;31mThe source of truth for '$file' is in AOSP.\033[0m"
+        echo -e "\033[0;31;47mThe source of truth for '$file' is in AOSP.\033[0m"
         (( count++ ))
     done < <(git show --name-only --pretty=format: $1 | grep -- "$2")
     if (( count != 0 )); then
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 4c741c4..fe6ca55 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -72,7 +72,7 @@
 
     SourceLocation loc;
     if (field->GetSourceLocation(&loc)) {
-        // TODO: this will work if we can figure out how to pass
+        // TODO(b/162454173): this will work if we can figure out how to pass
         // --include_source_info to protoc
         fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
     } else {
@@ -111,7 +111,6 @@
         case FieldDescriptor::TYPE_GROUP:
             return JAVA_TYPE_UNKNOWN;
         case FieldDescriptor::TYPE_MESSAGE:
-            // TODO: not the final package name
             if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
                 return JAVA_TYPE_ATTRIBUTION_CHAIN;
             } else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
@@ -147,7 +146,7 @@
 void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
     for (int i = 0; i < enumDescriptor.value_count(); i++) {
         atomField->enumValues[enumDescriptor.value(i)->number()] =
-                enumDescriptor.value(i)->name().c_str();
+                enumDescriptor.value(i)->name();
     }
 }
 
@@ -528,7 +527,7 @@
 
         vector<java_type_t> signature;
         errorCount += collate_atom(atom, atomDecl.get(), &signature);
-        if (atomDecl->primaryFields.size() != 0 && atomDecl->exclusiveField == 0) {
+        if (!atomDecl->primaryFields.empty() && atomDecl->exclusiveField == 0) {
             print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
                         atomField->name().c_str());
             errorCount++;
@@ -541,8 +540,7 @@
                         atomField->name().c_str());
             errorCount++;
             continue;
-        }
-        else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
+        } else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
                  (oneofAtom->name() != ONEOF_PULLED_ATOM_NAME)) {
             print_error(atomField, "Atom is neither a pushed nor pulled atom: %s\n",
                         atomField->name().c_str());
@@ -578,7 +576,7 @@
             printf("   ");
             for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
                  jt++) {
-                printf(" %d", (int)*jt);
+                printf(" %d", static_cast<int>(*jt));
             }
             printf("\n");
         }
@@ -589,7 +587,7 @@
             printf("   ");
             for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
                  jt++) {
-                printf(" %d", (int)*jt);
+                printf(" %d", static_cast<int>(*jt));
             }
             printf("\n");
         }
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index e637ed9..5d196c4 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -47,8 +47,8 @@
  *
  * `OneofDescriptor::name()` returns the name of the oneof.
  */
-const string ONEOF_PUSHED_ATOM_NAME = "pushed";
-const string ONEOF_PULLED_ATOM_NAME = "pulled";
+const char ONEOF_PUSHED_ATOM_NAME[] = "pushed";
+const char ONEOF_PULLED_ATOM_NAME[] = "pulled";
 
 enum AnnotationId : uint8_t {
     ANNOTATION_ID_IS_UID = 1,
@@ -63,7 +63,7 @@
 
 const int ATOM_ID_FIELD_NUMBER = -1;
 
-const string DEFAULT_MODULE_NAME = "DEFAULT";
+const char DEFAULT_MODULE_NAME[] = "DEFAULT";
 
 /**
  * The types for atom parameters.
@@ -95,9 +95,9 @@
     int intValue;
     bool boolValue;
 
-    AnnotationValue(const int value) : intValue(value) {
+    explicit AnnotationValue(const int value) : intValue(value) {
     }
-    AnnotationValue(const bool value) : boolValue(value) {
+    explicit AnnotationValue(const bool value) : boolValue(value) {
     }
 };
 
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index ffbe9f8..6fcf267 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -42,6 +42,7 @@
 static void write_java_annotation_constants(FILE* out) {
     fprintf(out, "    // Annotation constants.\n");
 
+    const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
     for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
         fprintf(out, "    public static final byte %s = %hhu;\n", name.c_str(), id);
     }
@@ -56,6 +57,7 @@
         return;
     }
     const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
+    const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
     for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
         const string atomConstant = make_constant_name(atomDecl->name);
         fprintf(out, "        if (%s == code) {\n", atomConstant.c_str());
@@ -102,7 +104,7 @@
     for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
          arg++) {
         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-            for (auto chainField : attributionDecl.fields) {
+            for (const auto& chainField : attributionDecl.fields) {
                 fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
                         chainField.name.c_str());
             }
@@ -243,13 +245,15 @@
     return 0;
 }
 
-static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+static int write_java_pushed_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
                               const AtomDecl& attributionDecl, const bool supportQ) {
     for (auto signatureInfoMapIt = signatureInfoMap.begin();
          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
         // Print method signature.
         fprintf(out, "    public static void write(int code");
-        write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+        const vector<java_type_t>& signature = signatureInfoMapIt->first;
+        const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+        write_method_signature(out, signature, attributionDecl);
         fprintf(out, ") {\n");
 
         // Print method body.
@@ -259,7 +263,7 @@
             indent = "    ";
         }
 
-        int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+        int ret = write_method_body(out, signature, fieldNumberToAtomDeclSet,
                                     attributionDecl, indent);
         if (ret != 0) {
             return ret;
@@ -274,8 +278,8 @@
             fprintf(out, "        } else {\n");
             fprintf(out, "            QLogger.write(code");
             int argIndex = 1;
-            for (vector<java_type_t>::const_iterator arg = signatureInfoMapIt->first.begin();
-                 arg != signatureInfoMapIt->first.end(); arg++) {
+            for (vector<java_type_t>::const_iterator arg = signature.begin();
+                 arg != signature.end(); arg++) {
                 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                     const char* uidName = attributionDecl.fields.front().name.c_str();
                     const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -299,18 +303,20 @@
     return 0;
 }
 
-static int write_java_build_stats_event_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+static int write_java_pulled_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
                               const AtomDecl& attributionDecl) {
     for (auto signatureInfoMapIt = signatureInfoMap.begin();
          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
         // Print method signature.
         fprintf(out, "    public static StatsEvent buildStatsEvent(int code");
-        write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+        const vector<java_type_t>& signature = signatureInfoMapIt->first;
+        const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+        write_method_signature(out, signature, attributionDecl);
         fprintf(out, ") {\n");
 
         // Print method body.
         string indent("");
-        int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+        int ret = write_method_body(out, signature, fieldNumberToAtomDeclSet,
                                     attributionDecl, indent);
         if (ret != 0) {
             return ret;
@@ -357,9 +363,9 @@
 
     // Print write methods.
     fprintf(out, "    // Write methods\n");
-    errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+    errors += write_java_pushed_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
     errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
-    errors += write_java_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+    errors += write_java_pulled_methods(out, atoms.pulledAtomsSignatureInfoMap,
                                                    attributionDecl);
     if (supportWorkSource) {
         errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 8b3b505..afd992b 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
+#define ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
 
 #include <stdio.h>
 #include <string.h>
@@ -28,11 +29,11 @@
 namespace android {
 namespace stats_log_api_gen {
 
-using namespace std;
-
 int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
                          const string& javaClass, const string& javaPackage, const bool supportQ,
                          const bool supportWorkSource);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
+
+#endif  // ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index d21e270..be7cb4a 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -65,7 +65,7 @@
         for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
              arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                for (auto chainField : attributionDecl.fields) {
+                for (const auto& chainField : attributionDecl.fields) {
                     fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
                             chainField.name.c_str());
                 }
@@ -407,7 +407,7 @@
     if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
         fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
                 indent.c_str());
-        for (auto chainField : attributionDecl.fields) {
+        for (const auto& chainField : attributionDecl.fields) {
             fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
         }
         fprintf(out, ") {\n");
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index c511a84..622ef3e 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
+#define ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
 
 #include <stdio.h>
 #include <string.h>
@@ -28,8 +29,6 @@
 namespace android {
 namespace stats_log_api_gen {
 
-using namespace std;
-
 void write_java_q_logging_constants(FILE* out, const string& indent);
 
 int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap,
@@ -44,3 +43,5 @@
 
 }  // namespace stats_log_api_gen
 }  // namespace android
+
+#endif  // ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index b888ce9..2830249 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -15,9 +15,6 @@
 #include "native_writer.h"
 #include "utils.h"
 
-using namespace google::protobuf;
-using namespace std;
-
 namespace android {
 namespace stats_log_api_gen {
 
@@ -145,7 +142,7 @@
         index++;
     }
 
-    if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0) {
+    if (cppFilename.empty() && headerFilename.empty() && javaFilename.empty()) {
         print_usage();
         return 1;
     }
@@ -175,9 +172,9 @@
                  &attributionSignature);
 
     // Write the .cpp file
-    if (cppFilename.size() != 0) {
+    if (!cppFilename.empty()) {
         FILE* out = fopen(cppFilename.c_str(), "w");
-        if (out == NULL) {
+        if (out == nullptr) {
             fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
             return 1;
         }
@@ -198,9 +195,9 @@
     }
 
     // Write the .h file
-    if (headerFilename.size() != 0) {
+    if (!headerFilename.empty()) {
         FILE* out = fopen(headerFilename.c_str(), "w");
-        if (out == NULL) {
+        if (out == nullptr) {
             fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
             return 1;
         }
@@ -214,24 +211,24 @@
     }
 
     // Write the .java file
-    if (javaFilename.size() != 0) {
-        if (javaClass.size() == 0) {
+    if (!javaFilename.empty()) {
+        if (javaClass.empty()) {
             fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
             return 1;
         }
 
-        if (javaPackage.size() == 0) {
+        if (javaPackage.empty()) {
             fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
             return 1;
         }
 
-        if (moduleName.size() == 0) {
+        if (moduleName.empty()) {
             fprintf(stderr, "Must supply --module if supplying a Java filename");
             return 1;
         }
 
         FILE* out = fopen(javaFilename.c_str(), "w");
-        if (out == NULL) {
+        if (out == nullptr) {
             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
             return 1;
         }
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 21e88b3..b4fb8dd 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -24,6 +24,7 @@
 static void write_native_annotation_constants(FILE* out) {
     fprintf(out, "// Annotation constants.\n");
 
+    const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
     for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
         fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
     }
@@ -39,6 +40,7 @@
         return;
     }
     const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
+    const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
     for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
         const string atomConstant = make_constant_name(atomDecl->name);
         fprintf(out, "    if (%s == code) {\n", atomConstant.c_str());
@@ -60,8 +62,6 @@
                     }
                     break;
                 case ANNOTATION_TYPE_BOOL:
-                    // TODO(b/151786433): Write annotation constant name instead of
-                    // annotation id literal.
                     fprintf(out, "        %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(),
                             methodSuffix.c_str(), annotationConstant.c_str(),
                             annotation->value.boolValue ? "true" : "false");
@@ -145,7 +145,8 @@
         vector<java_type_t> signature = signatureInfoMapIt->first;
         const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
         // Key value pairs not supported in native.
-        if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+        if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+            signature.end()) {
             continue;
         }
         write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
@@ -219,7 +220,8 @@
          signature_it != signatureInfoMap.end(); signature_it++) {
         vector<java_type_t> signature = signature_it->first;
         // Key value pairs not supported in native.
-        if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+        if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+            signature.end()) {
             continue;
         }
 
@@ -258,7 +260,8 @@
         vector<java_type_t> signature = signatureInfoMapIt->first;
         const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
         // Key value pairs not supported in native.
-        if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+        if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+            signature.end()) {
             continue;
         }
         write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
@@ -285,7 +288,8 @@
         vector<java_type_t> signature = signatureInfoMapIt->first;
 
         // Key value pairs not supported in native.
-        if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+        if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+            signature.end()) {
             continue;
         }
         write_native_method_signature(out, methodName, signature, attributionDecl, ";");
diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h
index 264d4db..4e42d1f 100644
--- a/tools/stats_log_api_gen/native_writer.h
+++ b/tools/stats_log_api_gen/native_writer.h
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
+#define ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
 
 #include <stdio.h>
 #include <string.h>
@@ -24,8 +25,6 @@
 namespace android {
 namespace stats_log_api_gen {
 
-using namespace std;
-
 int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
                         const string& cppNamespace, const string& importHeader,
                         const bool supportQ);
@@ -35,3 +34,5 @@
 
 }  // namespace stats_log_api_gen
 }  // namespace android
+
+#endif  // ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 5fd728a..6f78921 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -24,7 +24,6 @@
 namespace stats_log_api_gen {
 
 using std::map;
-using std::set;
 using std::vector;
 
 /**
@@ -32,11 +31,11 @@
  */
 static bool map_contains_vector(const SignatureInfoMap& s, int count, ...) {
     va_list args;
-    vector<java_type_t> v;
+    vector<java_type_t> v(count);
 
     va_start(args, count);
     for (int i = 0; i < count; i++) {
-        v.push_back((java_type_t)va_arg(args, int));
+        v[i] = static_cast<java_type_t>(va_arg(args, int));
     }
     va_end(args);
 
@@ -222,7 +221,7 @@
     Atoms atoms;
     int errorCount =
             collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-    EXPECT_TRUE(errorCount > 0);
+    EXPECT_GT(errorCount, 0);
 }
 
 TEST(CollationTest, PassOnLogFromModuleAtom) {
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 4b37340..1eaf42a 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -16,11 +16,30 @@
 
 #include "utils.h"
 
-#include "android-base/strings.h"
-
 namespace android {
 namespace stats_log_api_gen {
 
+/**
+ * Inlining this method because "android-base/strings.h" is not available on
+ * google3.
+ */
+static vector<string> Split(const string& s, const string& delimiters) {
+    GOOGLE_CHECK_NE(delimiters.size(), 0U);
+
+    vector<string> result;
+
+    size_t base = 0;
+    size_t found;
+    while (true) {
+        found = s.find_first_of(delimiters, base);
+        result.push_back(s.substr(base, found - base));
+        if (found == s.npos) break;
+        base = found + 1;
+    }
+
+    return result;
+}
+
 static void build_non_chained_decl_map(const Atoms& atoms,
                                        std::map<int, AtomDeclSet::const_iterator>* decl_map) {
     for (AtomDeclSet::const_iterator atomIt = atoms.non_chained_decls.begin();
@@ -29,6 +48,20 @@
     }
 }
 
+const map<AnnotationId, string>& get_annotation_id_constants() {
+    static const map<AnnotationId, string>* ANNOTATION_ID_CONSTANTS =
+        new map<AnnotationId, string>{
+            {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
+            {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
+            {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
+            {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
+            {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
+            {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
+            {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
+
+    return *ANNOTATION_ID_CONSTANTS;
+}
+
 /**
  * Turn lower and camel case into upper case with underscores.
  */
@@ -102,15 +135,15 @@
 // Writes namespaces for the cpp and header files, returning the number of
 // namespaces written.
 void write_namespace(FILE* out, const string& cppNamespaces) {
-    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
-    for (string cppNamespace : cppNamespaceVec) {
+    vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
+    for (const string& cppNamespace : cppNamespaceVec) {
         fprintf(out, "namespace %s {\n", cppNamespace.c_str());
     }
 }
 
 // Writes namespace closing brackets for cpp and header files.
 void write_closing_namespace(FILE* out, const string& cppNamespaces) {
-    vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+    vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
     for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
         fprintf(out, "} // namespace %s\n", it->c_str());
     }
@@ -123,7 +156,7 @@
     for (vector<AtomField>::const_iterator field = atom->fields.begin();
          field != atom->fields.end(); field++) {
         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-            for (auto chainField : attributionDecl.fields) {
+            for (const auto& chainField : attributionDecl.fields) {
                 if (chainField.javaType == JAVA_TYPE_STRING) {
                     fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
                             chainField.name.c_str());
@@ -190,7 +223,7 @@
     for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
          arg++) {
         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-            for (auto chainField : attributionDecl.fields) {
+            for (const auto& chainField : attributionDecl.fields) {
                 if (chainField.javaType == JAVA_TYPE_STRING) {
                     fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
                             chainField.name.c_str());
@@ -222,7 +255,7 @@
     for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
          arg++) {
         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-            for (auto chainField : attributionDecl.fields) {
+            for (const auto& chainField : attributionDecl.fields) {
                 if (chainField.javaType == JAVA_TYPE_STRING) {
                     fprintf(out, ", %s", chainField.name.c_str());
                 } else {
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index 42dc90e..13a7e2d 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_UTILS_H
+#define ANDROID_STATS_LOG_API_GEN_UTILS_H
 
 #include <stdio.h>
 #include <string.h>
@@ -28,23 +29,14 @@
 namespace android {
 namespace stats_log_api_gen {
 
-using namespace std;
-
-const string DEFAULT_CPP_NAMESPACE = "android,util";
-const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+const char DEFAULT_CPP_NAMESPACE[] = "android,util";
+const char DEFAULT_CPP_HEADER_IMPORT[] = "statslog.h";
 
 const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
 const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
 const int JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS = 0x04;
 
-const map<AnnotationId, string> ANNOTATION_ID_CONSTANTS = {
-        {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
-        {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
-        {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
-        {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
-        {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
-        {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
-        {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
+const map<AnnotationId, string>& get_annotation_id_constants();
 
 string make_constant_name(const string& str);
 
@@ -81,3 +73,5 @@
 
 }  // namespace stats_log_api_gen
 }  // namespace android
+
+#endif  // ANDROID_STATS_LOG_API_GEN_UTILS_H